Java8之函数式编程

Java8之函数式编程

Lambda 表达式,也可称为闭包,它是推动 Java 8 发布的最重要新特性。

Lambda 允许把函数作为一个方法的参数(函数作为参数传递进方法中)。

使用 Lambda 表达式可以使代码变的更加简洁紧凑。

1.Lambda表达式

如下案例所示,分别创建三个接口,每个接口中只有一个方法,通过lambda表达式重写接口中的方法,可极大的简化代码。当只有一个入参时,则无需写 () 当表达式只有一行时则无需写 {}return

/**
 * @author kenewstar
 * @date 2022/01/23
 */
public class TestFunc1 {

	/**
	 * 相当于接口实现类
	 * 当接口只有一个方法时可用Lambda表达式简写接口实现
	 */
	static Aa aa = () -> System.out.println("打印Aa");
	static Ab ab = () -> "返回Ab";
	static Ac ac = name -> name + ":说话";
	static Ac ac2 = name -> {
		System.out.println("入参:" + name);
		return name + ": 我是Ac";
	};

	public static void main(String[] args) {

		aa.testAa();
		System.out.println(ab.testAb());
		System.out.println(ac.testAc("kenewstar"));
		System.out.println(ac2.testAc("k2"));

	}

}

interface Aa {
   void testAa();
}
interface Ab {
   String testAb();
}
interface Ac {
   String testAc(String name);
}

执行结果:

打印Aa
返回Ab
kenewstar:说话
入参:k2
k2: 我是Ac

任何 Lambda 表达式的基本语法是:

  1. 参数。 2. 接着 -> ,可视为“产出”。 3. -> 之后的内容都是方法体。

2.方法引用

除了可以使用Lambda表达式重写接口方法外,还可使用方法引用的方式重写接口方法,使用前提也必须是该接口是一个函数式接口,即接口中只有一个方法(抽象方法),因为Java8允许接口中有静态方法和默认方法。

如下案例使用Lambda表达式与方法引用重写同一个方法。

/**
 * 方法引用
 * @author kenewstar
 * @date 2022/01/23
 */
public class TestFunc2 {

   static String returnStr() {
      return "call2";
   }

   static void printRunnable() {
      System.out.println("打印Runnable2");
   }

   public static void main(String[] args) throws Exception {

      // Callable函数式接口,
      // Lambda表达式 无入参,有返参
      Callable<String> c = () -> "call";
      System.out.println(c.call());
      // 方法引用重写接口
      // 调用了一个只有返回值的方法
      Callable<String> c2 = TestFunc2::returnStr;
      System.out.println(c2.call());

      // Runnable函数式接口
	  Runnable r = () -> System.out.println("打印Runnable");
	  r.run();
	  // 方法引用重写接口
	  // 调用了一个无入参,无返参的方法
	  Runnable r2 = TestFunc2::printRunnable;
	  r2.run();

   }

}

执行结果:

call
call2
打印Runnable
打印Runnable2

注意 : 方法引用中重写的方法必须与函数式接口的方法类型格式保持一致,入参返参的顺序及类型都必须一致,才可使用该方法引用。

Runnable接口的一个简化示例

匿名内部类 -> lambda表达式 -> 方法引用

/**
 * @author kenewstar
 * @date 2022/01/23
 */
public class TestFunc3 {
   
   static void run() {
      System.out.println("方法引用");
   }

   public static void main(String[] args) {
      // 使用匿名内部类的方式重写接口
      new Thread(new Runnable() {
         @Override
         public void run() {
            System.out.println("匿名内部类");
         }
      }).start();
      // 使用Lambda方式重写接口
      new Thread(() -> System.out.println("Lambda表达式")).start();
      // 使用方法引用的方式
      new Thread(TestFunc3::run).start();
   }
   
   
}

执行结果:

匿名内部类
Lambda表达式
方法引用

未绑定的方法引用

未绑定的方法引用是指没有关联对象的普通(非静态)方法。 使用未绑定的引用时,我们必须先提供对象:

我们先来看一个例子:

/**
 * @author @author kenewstar
 * @date 2022/01/23
 */
public class TestFun4 {

   public static void main(String[] args) {
      // Non-static method cannot be referenced from a static context
      // TestFa fa = MethodRef::test;

      TestFb fb = MethodRef::test;
      MethodRef ref = new MethodRef();
      System.out.println(fb.tf(ref));
      
      // 或者使用 对象::方法的方式
      TestFa fa = ref::test;
      System.out.println(fa.tf());

   }

}

class MethodRef {
   public String test() {
      return "test";
   }
}
interface TestFa {
   String tf();
}
interface TestFb {
   String tf(MethodRef ref);
}

我们看到上面无法将 **MethodRef::test **函数式引用绑定到 TestFa 接口上,这是因为实际上还有另一个隐藏的参数: this 。 你不能在没有 MethodRef 对象的前提下调用 test() 。 因此,MethodRef::test 表示未绑定的方法引用,因为它尚未“绑定”到对象,如果使用 ref::test 方式则等同于已绑定的方法引用。

使用未绑定的引用时,函数式方法的签名(接口中的单个方法)不再与方法引用的签名完全匹配,因此需要一个额外的 MethodRef 参数对象。原因是:你需要一个对象来调用方法。

如果有多个参数,则默认第一个参数传递 this 对象

/**
 * @author kenewstar
 * @date 2022/01/23
 */
public class TestFunc4 {

	public static void main(String[] args) {

		TestFc fc = MethodRef::test;
        MethodRef ref = new MethodRef();
		System.out.println(fc.tf(ref, "other"));

	}

}

class MethodRef {

	public String test(String name) {
		return "test + " + name;
	}
}
interface TestFc {
	String tf(MethodRef ref, String other);
}

构造函数引用

即通过构造方法的引用创建对象

/**
 * @author kenewstar
 * @date 2022/01/23
 */
public class TestFunc5 {

   public static void main(String[] args) {

      CreatePerson cp = Person::new;
      Person kenewstar = cp.create("kenewstar", 22);
      System.out.println(kenewstar);

   }
}

interface CreatePerson {
   Person create(String name, int age);
}
class Person {
   String name;
   int age;

   public Person(String name, int age) {
      this.name = name;
      this.age = age;
   }
}

方法引用的三种方式:

类名::方法名

对象名::方法名

构造方法名:: new

3.函数式接口

@FunctionalInterface 一个被该注解标注的接口则表示它是一个函数式接口,该接口中只允许一个抽象方法的存在,存在多个则会编译不通过。例如前面例子中所提到的Runnable, Callable接口都是函数式接口

Java8提供函数式接口

特征函数式方法名示例
无参数; 无返回值Runnable run()Runnable
无参数; 返回类型任意Supplier get()Supplier BooleanSupplier IntSupplier LongSupplier DoubleSupplier
无参数; 返回类型任意Callable call()Callable
1 个参数; 无返回值Consumer accept()Consumer IntConsumer LongConsumer DoubleConsumer
2 个参数 ;ConsumerBiConsumer accept()BiConsumer<T, U>
2 个参数 Consumer; 1 引用; 1 基本类型Obj类型Consumer accept()ObjIntConsumer ObjLongConsumer ObjDoubleConsumer
1 个参数; 返回类型不同Function apply() To类型 和 类型To类型Function IntFunction LongFunction DoubleFunction ToIntFunction ToLongFunction ToDoubleFunction IntToLongFunction IntToDoubleFunction LongToIntFunction LongToDoubleFunction DoubleToIntFunction DoubleToLongFunction
1个 参数; 返回类型相同UnaryOperator apply()UnaryOperator IntUnaryOperator LongUnaryOperator DoubleUnaryOperator
2 个参数类型相同; 返回类型相同Comparator compare()Comparator
2 个参数; 返回布尔型Predicate test()Predicate BiPredicate IntPredicate LongPredicate DoublePredicate
参数基本类型; 返回基本类型类型To类型Function applyAs类型()IntToLongFunction IntToDoubleFunction LongToIntFunction LongToDoubleFunction DoubleToIntFunction DoubleToLongFunction
2 个参数类型不同Bi操作 (不同方法名)BiFunction BiConsumer BiPredicate ToIntBiFunction ToLongBiFunction ToDoubleBiFunction

3.1 Supplier

/**
 * @author kenewstar
 * @date 2022/01/23
 */
public class TestSupplier {

	static Supplier<String> s = () -> "我是Supplier型接口";
	static BooleanSupplier bs = () -> true;
	static IntSupplier is = () -> 100;
	static LongSupplier ls = () -> 100L;
	static DoubleSupplier ds = () -> 100.00;

	public static void main(String[] args) {
		// Supplier类型
		System.out.println(s.get());           // 我是Supplier型接口
		System.out.println(bs.getAsBoolean()); // true
		System.out.println(is.getAsInt());     // 100
		System.out.println(ls.getAsLong());    // 100
		System.out.println(ds.getAsDouble());  // 100.0

	}
}

3.2 Consumer

/**
 * @author kenewstar
 * @date 2022/01/23
 */
public class TestConsumer {

   static Consumer<String> c = str -> System.out.println("consumer " + str);
   static IntConsumer ic = i -> System.out.println(i * 100);
   static LongConsumer lc = l -> System.out.println(l * 100);
   static DoubleConsumer dc = d -> System.out.println(d * 100);

   public static void main(String[] args) {
      
      // Consumer类型
      c.accept("kns");   // consumer kns
      ic.accept(2);      // 200
      lc.accept(3L);     // 300
      dc.accept(4D);     // 400.0

   }
}

3.3 BiConsumer

/**
 * @author kenewstar
 * @date 2022/01/23
 */
public class TestBiConsumer {

   static BiConsumer<String, Integer> bc = (str, i) -> {
		Integer result;
		try {
			result = Integer.parseInt(str);
		} catch (Exception e) {
			result = 0;
		}
		System.out.println(result + i);
	};

   public static void main(String[] args) {
      
        bc.accept("100", 200);  // 300

   }
}

3.4 ObjConsumer

/**
 * @author kenewstar
 * @date 2022/01/23
 */
public class TestObjConsumer {

   static ObjIntConsumer<String> oic = (o, i) -> System.out.println(o + i);
   static ObjLongConsumer<String> olc = (o, l) -> System.out.println(o + l);
   static ObjDoubleConsumer<String> odc = (o, d) -> System.out.println(o + d);

   public static void main(String[] args) {

      oic.accept("obj", 100);    // obj100
      olc.accept("obj", 100L);   // obj100
      odc.accept("obj", 100.0);  // obj100.0

   }
}

3.5 Function

/**
 * @author kenewstar
 * @date 2022/01/23
 */
public class TestFunction {

   static Function<String, String> func = s -> s;
   // 将数字转换为字符串
   static IntFunction<String> iFunc = String::valueOf;
   static LongFunction<String> lFunc = String::valueOf;
   static DoubleFunction<String> dFunc = String::valueOf;
   // 将字段串转换为数字类型
   static ToIntFunction<String> tif = Integer::parseInt;
   static ToLongFunction<String> tlf = Long::parseLong;
   static ToDoubleFunction<String> tdf = Double::parseDouble;

   // 将类型转换另一个类型
   static IntToLongFunction ilf = i -> i;
   static IntToDoubleFunction idf = i -> i;
   static LongToIntFunction lif = l -> (int)l;
   static LongToDoubleFunction ldf = l -> l;
   static DoubleToIntFunction dif = d -> (int)d;
   static DoubleToLongFunction dlf = d -> (long)d;

   public static void main(String[] args) {
      System.out.println(func.apply("abc"));
      System.out.println(iFunc.apply(100));
      System.out.println(lFunc.apply(200L));
      System.out.println(dFunc.apply(300.0));

      System.out.println(tif.applyAsInt("111"));
      System.out.println(tlf.applyAsLong("222"));
      System.out.println(tdf.applyAsDouble("333"));

      System.out.println(ilf.applyAsLong(100));
      System.out.println(idf.applyAsDouble(100));
      System.out.println(lif.applyAsInt(200L));
      System.out.println(ldf.applyAsDouble(200L));
      System.out.println(dif.applyAsInt(300.0));
      System.out.println(dlf.applyAsLong(300.0));

   }

}

3.6 UnaryOperator

/**
 * 继承自Function
 * 入参返参相同
 * @author kenewstar
 * @date 2022/01/23
 */
public class TestUnaryOperator {

   static UnaryOperator<String> uo = s -> s;
   static IntUnaryOperator iuo = i -> i * 2;
   static LongUnaryOperator luo = l -> l * 2;
   static DoubleUnaryOperator duo = d -> d * 2;

   public static void main(String[] args) {

      System.out.println(uo.apply("I am kns"));
      System.out.println(iuo.applyAsInt(100));
      System.out.println(luo.applyAsLong(200));
      System.out.println(duo.applyAsDouble(300.0));
   }
}

3.7 BinaryOperator

/**
 * @author kenewstar
 * @date 2022/01/23
 */
public class TestBinaryOperator {

   static BinaryOperator<String> bo = (s1, s2) -> s1 + s2;
   static IntBinaryOperator ibo = Integer::sum;
   static LongBinaryOperator lbo = Long::sum;
   static DoubleBinaryOperator dbo = Double::sum;

   public static void main(String[] args) {

      System.out.println(bo.apply("I am", " kns"));
      System.out.println(ibo.applyAsInt(12, 23));
      System.out.println(lbo.applyAsLong(24, 46));
      System.out.println(dbo.applyAsDouble(36, 69));

   }

}

3.8 Comparator

/**
 * 比较器类型
 * @author kenewstar
 * @date 2022/01/23
 */
public class TestComparator {

   static Comparator<Integer> comparator = Integer::compareTo;

   public static void main(String[] args) {
      System.out.println(comparator.compare(10, 12));
   }

}

3.9 Predicate

/**
 * 断言型函数式接口 返回boolean值
 * @author kenewstar
 * @date 2022/01/23
 */
public class TestPredicate {

   static Predicate<String> p = Objects::nonNull;
   static BiPredicate<String, String> eq = Objects::equals;
   static IntPredicate ip = i -> i > 100;
   static LongPredicate lp = l -> l > 200;
   static DoublePredicate dp = d -> d > 300;

   public static void main(String[] args) {

      // 是否不为Null对象
      System.out.println(p.test("abc"));
      System.out.println(eq.test("abc", "abc"));
      System.out.println(ip.test(200));
      System.out.println(lp.test(200));
      System.out.println(dp.test(200));

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值