一、基础
基本语法
[接口声明] = (参数)-> {代码。。。};
具体使用
1.表达式必须和接口绑定使用,符合接口的方法声明。
如某个接口:
public interface A {
String get(int i);
}
声明接口时:
A a = new A() {
@Override
public String get(int i) {
return "hello " + i;
}
};
使用lambda
A la = (int i) -> {
return "lambda " + i;
};
但如果一个接口有多个方法,则无法使用lambda表达式。如
public interface B {
String get(int i);
void set();
}
default和static方法除外
public interface A {
String get(int i);
default int fun1() {
return 0;
}
static String fun2() {
return "A";
}
}
2.参数:可以是0到n个参数,具体根据绑定的接口而定,且参数类型可以不写。
A la = (i) -> {
return "lambda " + i;
};
3.返回值:如果代码块只有一行,可以没有大括号。
没有大括号时,不能用return关键字。
如果添加了大括号,或者有多行代码,必须通过关键字return返回。
//可以这样
A la2 = (i) -> "lambda " + i;
//也可以这样
A la2 = (i) -> {
return "lambda " + i;
};
//而不能这样
A la2 = (i) -> return "lambda " + i;
java.util.function提供了大量的函数式接口供我们使用
Predicate,传入T类型,返回boolean
Consumer,传入T类型,消耗掉,返回void
function,传入T类型,返回E类型
Supplier,传入返回T类型
UnaryOperator,传入T,返回T
BinaryOperator,传入两个T类型,返回T类型
emmm,记不住~~~
如Predicate
Predicate<String> pre1 = (name) -> "admin".equals(name);
System.out.println(pre1.test("admin") ? "管理员" : "普通用户");
打印结果:
管理员
lambda对this关键字的优化
使用lambda表达式时,在表达式内部this代表的是该lambda表达式所属的对象。
正常情况下,在接口内部使用this,该this指的是这个接口,而不是声明该接口的对象(或者说该接口所属的对象)
public class Test{
String s1 = "全局变量";
public void testLambda() {
String s2 = "局部变量";
new Thread(new Runnable() {
@Override
public void run() {
String s3 = "内部变量";
System.out.println(this.s1);//报错!!!
System.out.println(s2);
System.out.println(s3);
}
}).start();
}
public static void main(String[] args) {
new App().testLambda();
}
}
public class Test {
String s1 = "全局变量";
public void testLambda() {
String s2 = "局部变量";
new Thread(() -> {
String s3 = "内部变量";
System.out.println(this.s1);//不报错!!!
System.out.println(s2);
System.out.println(s3);
}).start();
}
public static void main(String[] args) {
new App().testLambda();
}
}
打印结果:
全局变量
局部变量
内部变量
方法重载对lambda表达式的影响
当遇到重载方法时,如果方法中传入的接口中的方法参数类型和返回值一样,则无法使用lambda。如
public class Test {
public static void main(String[] args) {
test(() ->{//报错!!!
System.out.println("I1");
return 1;
});
}
//重载方法
private static void test(A a) {
a.printString();
}
private static void test(B b) {
b.printInt();
}
}
interface A {
void printString();
}
interface B {
void printInt();
}
二、lambda在集合中的应用
方法引用
1. 静态方法、实例方法引用
以List.sort() 为例
实体类:
class Person {
private String name;
private int age;
public static int compareByAge(Person p1, Person p2) {
return p1.age - p2.age;
}
public Person() {
}
public Person(String name, int age) {
this.name = name;
this.age = age;
}
setter and getter...
@Override
public String toString() {
return "Person{" +
"name='" + name + '\'' +
", age=" + age +
'}';
}
}
数据源
List<Person> persons = new ArrayList<>();
persons.add(new Person("Tom", 28));
persons.add(new Person("Jack", 30));
persons.add(new Person("Dav", 20));
使用内部类方式
//使用内部类方式
persons.sort(new Comparator<Person>() {
@Override
public int compare(Person o1, Person o2) {
int i = o1.getAge() - o2.getAge();
return i;
}
});
使用lambda方式
//使用lambda方式
persons.sort((a, b) -> a.getAge() - b.getAge());
persons.sort(Comparator.comparingInt(Person::getAge));
先在任意一个类中定义参数为(Person p1, Person p2),返回类型为 int 的静态方法和普通方法
class PersonUtil {
public int compareByAge(Person p1, Person p2) {
return p1.getAge() - p2.getAge();
}
public static int compare(Person p1, Person p2) {
return p1.getAge() - p2.getAge();
}
}
静态方法引用,类名::静态方法名
//静态方法的引用,会默认将(Person, Person)参数传递给PersonUtil的compare方法
persons.sort(PersonUtil::compare);
实例方法引用,对象::普通方法名
//实例方法的引用
PersonUtil pu = new PersonUtil();
persons.sort(pu::compareByAge);
2. 构造方法引用
除了静态方法引用和实例方法引用还有构造方法引用。
interface IPerson {
//通过指定类型的构造方法初始化对象数据,
//即:Person类中必须有(String name, int age)类型参数的构造方法。
Person initPerson(String name, int age);
}
//构造方法的引用
IPerson ip = Person::new;
Person wang = ip.initPerson("wang", 25);
Stream
Stream解耦了对数据的各种操作,比起传统的手动操作数据更方便。
例如:
List<String> list = new ArrayList<>();
list.add("abc");
list.add("adcd");
list.add("adcde");
list.add("adcdef");
//传统方式获取list中元素长度>=4的数据
List<String> result = new ArrayList<>();
for (String s : list) {
if (s.length() >= 4) {
result.add(s);
}
}
System.out.println(result);
//使用Stream方式获取list中元素长度>=4的数据
List<String> collect = list.stream().filter(s -> s.length() >= 4).collect(Collectors.toList());
System.out.println(collect);
打印结果:
[adcd, adcde, adcdef]
[adcd, adcde, adcdef]
Stream概述
/**
* 1. 获取Stream对象
* 1. 从集合或数组中获取[**]
* Collection.stream(),如list.stream()
* Collection.parallelStream()
* Arrays.stream()
* 2. BufferReader
* BufferReader.lines()
* 3. 静态方法
* java.util.stream.IntStream.range()..
* java.nio.file.Files.walk()..
* 4. 自定义构建
* java.util.Spliterator
* 5. 更多方式。。
* Random.ints()
* Pattern.splitAsStream()..
* 2. 中间操作api
* 操作结果是一个Stream,中间操作可以有一个或多个连续的中间操作,需要注意的是,中间操作只记录操作方式,
* 不做具体执行,直到借宿操作发生时,才做数据的最终执行。
* 中间操作:就是业务逻辑处理。
* 中间操作过程:
* 无状态:数据处理是,不搜前置中间操作的影响。
* map/filter/peek/parallel/sequential/unordered
* 有状态:数据处理时,受前置中间操作的影响。
* distinct/sorted/limit/skip
* 3. 终结操作 | 结束操作{Terminal}
* 需要注意:一个Stream对象,只能由一个Terminal操作,这个操作一旦发生,就会真实的处理数据。
* 终结操作:
* 非短路操作:当前的Stream对象必须处理完集合中所有数据才能得到结果。
* forEach/forEachOrdered/toArray/reduce/collect/min/max/count/iterator
* 短路操作:当前的Stream对象在处理过程中,一旦满足某个条件,就可以得到结果。
* anyMatch/allMatch/noneMatch/findFirst/findAnd等
*/
对比上面例子
list.stream() //获取Stream
.filter(s -> s.length() >= 4) //中间操作,返回一个Stream对象
.collect(Collectors.toList()); //终结操作
Stream的获取
//多个数据
Stream<String> stream1 = Stream.of("A", "B", "C");
//数组
String[] strArray = new String[]{"A", "B", "C"};
Stream<String> stream2 = Stream.of(strArray);
//列表
ArrayList<Object> list = new ArrayList<>();
list.add("A");
list.add("B");
list.add("C");
Stream<Object> stream3= list.stream();
//集合
Set<String> set = new HashSet<>();
set.add("A");
set.add("B");
set.add("C");
Stream<String> stream4 = set.stream();
//map
HashMap<String, Integer> map = new HashMap<>();
map.put("A", 1);
map.put("B", 2);
map.put("C", 3);
Stream<Map.Entry<String, Integer>> stream5 = map.entrySet().stream();
Stream对象对于基本数据类型的封装
// int / long / double
IntStream.of(new int[] {10, 20, 30}).forEach(System.out::println);
IntStream.range(1,5).forEach(System.out::println);
IntStream.rangeClosed(1,5).forEach(System.out::println);
从Stream中获取指定的类型数据
Stream<String> stream1 = Stream.of("A", "B", "C");
//array
String[] arrayx = stream1.toArray(String[]::new);
//string
String stringx = stream1.collect(Collectors.joining());
//list
List<String> listx = stream1.collect(Collectors.toList());
//set
Set<String> setx = stream1.collect(Collectors.toSet());
//map
Map<String, String> mapx = stream1.collect(Collectors.toMap(x -> "key:" + x, y -> "val:" + y));
网友评论