Java基础教程——Lambda表达式

Lambda表达式

Java8引入Lambda表达式,可以使代码更简洁。

格式:参数,箭头,代码

(参数名)->{代码}

Lambda表达式体现了“函数式编程思想”——

面向对象的思想:找一个能解决问题的对象,调用对象完成事情。
函数式编程思想:只要结果,不管过程,不在乎是谁做、怎么做。


Lambda表达式的前提——函数式接口。

函数式接口,且只有一个未实现方法,可用注解@FunctionalInterface进行限定。
接口有且只有一个未实现方法,Lambda才能进行推导。
可以有其它非抽象方法,比如默认方法。


lambda表达式可推导、可省略:

  • 参数类型可以不写
  • 参数只有一个的话,类型和()都可以省略
  • 如果{}中的代码只有一行,可以省略{}、return、分号
package ah;
import java.util.*;
public class TestLambda {
	public static void main(String[] args) {
		System.out.println("---- 1.线程(无参数)");
		// |--(1.1)匿名内部类写法
		Thread t = new Thread(new Runnable() {
			@Override
			public void run() {
				System.out.println(Thread.currentThread());
			}
		});
		t.start();
		// |--(1.2)Lambda表达式写法
		Thread t2 = new Thread(() -> {
			System.out.println(Thread.currentThread());
		});
		t2.start();
		System.out.println("---- 2.集合排序(带参数)");
		List<Phone> lst = new ArrayList<>();
		lst.add(new Phone(1000, 300));
		lst.add(new Phone(2000, 200));
		lst.add(new Phone(3000, 100));
		// |--(2.1)匿名内部类写法
		Collections.sort(lst, new Comparator<Phone>() {
			@Override
			public int compare(Phone o1, Phone o2) {
				return (int) (o2.price - o1.price);
			}
		});
		System.out.println(lst);
		// |--(2.2)Lambda表达式写法
		Collections.sort(lst, (Phone o1, Phone o2) -> {
			return o2.hot - o1.hot;
		});
		System.out.println(lst);
		// |--(2.3)Lambda表达式省略写法(参数类型省略,{}、return、分号省略)
		Collections.sort(lst, (o1, o2) -> o1.hot - o2.hot);
		System.out.println(lst);
		System.out.println("---- 3.一个参数的场合:参数括号能省略");
		// |--(3.1)输出集合内容
		lst.forEach(s -> System.out.println(s));
		// |--(3.2)自定义接口和方法,参数使用接口
		testArgIsInterface(s -> System.out.println(s), 100);
	}
	static void testArgIsInterface(IoneArg arg, int n) {
		arg.m(n);
	}
}
class Phone {
	double price;
	int hot;
	public Phone(double price, int hot) {
		this.price = price;
		this.hot = hot;
	}
	@Override
	public String toString() {
		return "Phone [price=" + price + ", hot=" + hot + "]";
	}
}
@FunctionalInterface
interface IoneArg {
	void m(int n);
}
---- 1.线程(无参数)
Thread[Thread-0,5,main]
---- 2.集合排序(带参数)
Thread[Thread-1,5,main]
[Phone [price=3000.0, hot=100], Phone [price=2000.0, hot=200], Phone [price=1000.0, hot=300]]
[Phone [price=1000.0, hot=300], Phone [price=2000.0, hot=200], Phone [price=3000.0, hot=100]]
[Phone [price=3000.0, hot=100], Phone [price=2000.0, hot=200], Phone [price=1000.0, hot=300]]
---- 3.一个参数的场合:参数括号能省略
Phone [price=3000.0, hot=100]
Phone [price=2000.0, hot=200]
Phone [price=1000.0, hot=300]
100

Supplier接口

java.util.function 包下有很多函数式接口,比如:

@FunctionalInterface
public interface Supplier<T> {
    T get();
}

Supplier接口称为“生产型接口”,指定接口的泛型,get方法会产生相应类型的数据。

使用示例:

import java.util.function.Supplier;
public class TestSupplier {
	// 将Supplier类型作为参数,以便Lambda知道接口类型
	// 要实现的功能:获取数组的最大值
	static int getMax(Supplier<Integer> sup) {
		return sup.get();
	}
	public static void main(String[] args) {
		int arr[] = { 5, 3, 2, -5, 99, 76 };
		int maxOfArr = getMax(() -> {
			int max = arr[0];
			for (int n : arr) {
				max = max < n ? n : max;
			}
			return max;
		});
		System.out.println(maxOfArr);
	}
}
99

Consumer接口

和Supplier接口相对,用于“消费”,接受参数用于处理。addThen方法用于连续处理。

@FunctionalInterface
public interface Consumer<T> {
    void accept(T t);

    default Consumer<T> andThen(Consumer<? super T> after) {
        Objects.requireNonNull(after);
        return (T t) -> { accept(t); after.accept(t); };
    }
}

Consumer示例:

import java.util.function.Consumer;
public class TestConsumer {
	public static void main(String[] args) {
		testAccept((str) -> {
			System.out.println(str);
		}, "孙行者");
		testAndThen((str) -> System.out.println("A" + str),
				(str) -> System.out.println(str + "Z"), "猪悟能");
	}
	static void testAccept(Consumer<String> c, String s) {
		// accept接受数据:可以使用数据(相当于消费)
		c.accept(s);
	}
	static void testAndThen(Consumer<String> c1, Consumer<String> c2, String s) {
		c1.accept(s);
		c2.accept(s);
		System.out.println("---default andThen:相当于把两个Consumer连起来使用");
		c1.andThen(c2).accept(s);
		System.out.println("---连接分先后,参数为后");
		c2.andThen(c1).accept(s);
	}
}

孙行者
A猪悟能
猪悟能Z
---default andThen:相当于把两个Consumer连起来使用
A猪悟能
猪悟能Z
---连接分先后,参数为后
猪悟能Z
A猪悟能

Predicate接口

predicate:谓词。指boolean-valued,主要有ADD,OR,NOT

源码:

@FunctionalInterface
public interface Predicate<T> {
    boolean test(T t);
    default Predicate<T> and(Predicate<? super T> other) {
        Objects.requireNonNull(other);
        return (t) -> test(t) && other.test(t);
    }
    default Predicate<T> negate() {
        return (t) -> !test(t);
    }
    default Predicate<T> or(Predicate<? super T> other) {
        Objects.requireNonNull(other);
        return (t) -> test(t) || other.test(t);
    }
    static <T> Predicate<T> isEqual(Object targetRef) {
        return (null == targetRef)
                ? Objects::isNull
                : object -> targetRef.equals(object);
    }
}

示例:对字符串进行判断

import java.util.function.Predicate;
public class TestPredicate {
	static void testTest(Predicate<String> p, String s) {
		System.out.println(p.test(s));
	}
	static void testAnd(Predicate<String> p1, Predicate<String> p2, String s) {
		System.out.println(p1.and(p2).test(s));
	}
	public static void main(String[] args) {
		testTest((s) -> s == null, "A");
		// 判断字符串不为null,同时长度>5
		testAnd(
		// 参数1:判断不为null
		(s) -> s != null,
		// 参数2:判断长度>5
				(s) -> s.length() > 5,
				// 参数3:
				"123456");
	}
}
false
true

示例:

import java.util.*;
import java.util.function.Predicate;
public class TestPredicate2 {
	// 对数组进行过滤,把符合条件的放入集合中
	static List<String> filter(Predicate<String> p1, Predicate<String> p2,
			String[] arr) {
		List<String> lst = new ArrayList<>();
		for (String str : arr) {
			if (p1.and(p2).test(str)) {
				lst.add(str);
			}
		}
		return lst;
	}
	public static void main(String[] args) {
		String[] s = { "关羽,蜀,武", "张飞,蜀,武", "典韦,魏,武", "诸葛亮,蜀,文" };
		// 将蜀国的文官放入列表
		List<String> lst = filter(
		// 参数1:一种操作
				(name) -> {
					String[] split = name.split(",");
					String nation = split[1];
					if ("蜀".equals(nation)) {
						return true;
					} else {
						return false;
					}
				},
				// 参数2:另一种操作
				(name) -> name.split(",")[2].equals("文"),
				// 参数3:被操作的字符串
				s);
		System.out.println(lst);
	}
}
[诸葛亮,蜀,文]

Function接口

根据一个类型的数据(前置条件)得到另一个类型的数据(后置条件)。

package java.util.function;
import java.util.Objects;
@FunctionalInterface
public interface Function<T, R> {
    
    R apply(T t);

    default <V> Function<V, R> compose(Function<? super V, ? extends T> before) {
        Objects.requireNonNull(before);
        return (V v) -> apply(before.apply(v));
    }

    default <V> Function<T, V> andThen(Function<? super R, ? extends V> after) {
        Objects.requireNonNull(after);
        return (T t) -> after.apply(apply(t));
    }

    static <T> Function<T, T> identity() {
        return t -> t;
    }
}

示例:

import java.util.function.Function;
public class TestFunction {
	static void testApply(Function<String, Integer> f, String s) {
		Integer n = f.apply(s);
		System.out.println(n);
	}
	static void testAddThen(Function<String, String> f1,
			Function<String, String> f2, Function<String, String> f3, String s) {
		// compose:组合,先做
		// addThen:后做
		String ret = f1.compose(f2).andThen(f3).apply(s);
		System.out.println(ret);
	}
	public static void main(String[] args) {
		String str = ">>1234";
		testApply(
		// 参数1:把字符串转换为整数
				s -> {
					s = s.substring(2);
					return Integer.parseInt(s);
				},
				// 参数2:要处理的字符串
				str);
		testAddThen(
		// 参数1
				s -> s + "【齐天大圣】",
				// 参数2:做了compose的参数(先做)
				s -> s + "【弼马温】",
				// 参数3:做了andThen参数(后做)
				s -> s + "【斗战胜佛】",
				// 参数四:字符串
				"孙悟空");
	}
}
1234
孙悟空【弼马温】【齐天大圣】【斗战胜佛】

延迟执行

有些场景下,代码执行后,结果不一定被使用,这将造成浪费。Lambda表达式是“延迟执行”的,正好作为解决方案,提升性能。

比如:

public class TestLambdaLazy {
	// 非Lambda参数,会产生字符串
	public static void log(int level, String msg) {
		if (level == 1) {
			System.out.println(msg);
		}
	}
	// Lambda表达式写法:参数改为函数式接口
	// 参数虽然传递(对象),但是不使用的时候不执行
	public static void log(int level, Message msg) {
		if (level == 1) {
			System.out.println(msg.setMsg());
		}
	}
	public static void main(String[] args) {
		int sum = 100;
		log(2, "总计:" + sum);// 其实没有打印,字符串徒劳拼接
		log(2, () -> {
			System.out.println("Lambda执行");
			return "总计:" + sum;
		});
	}
}
// Lambda用的函数式接口
interface Message {
	String setMsg();
}
posted @ 2019-07-14 00:56  虎老狮  阅读(500)  评论(0编辑  收藏  举报