JDK1.8新特性---lambda表达式

一、简介

函数式接口(Functional Interfaces):如果一个接口定义个唯一一个抽象方法,那么这个接口就成为函数式接口。同时,引入了一个新的注解:@FunctionalInterface。可以把他它放在一个接口前,表示这个接口是一个函数式接口。这个注解是非必须的,只要接口只包含一个方法的接口,虚拟机会自动判断,不过最好在接口上使用注解 @FunctionalInterface 进行声明。在接口中添加了 @FunctionalInterface 的接口,只允许有一个抽象方法,否则编译器也会报错。

@FunctionalInterface
public interface FunctionInterfaceDemo {
    void say(String name);
}

同时,Java 8允许我们给接口添加一个非抽象的方法实现,只需要使用 default关键字即可,这个特征又叫做扩展方法。还可以存在静态的方法。

@FunctionalInterface
public interface FunctionInterfaceDemo {
    void say(String name);
    
    default void print(String text) {
        System.out.println(text);
    };
    
    static void write(String message) {
        System.out.println(message);
    }
}

 

二、语法

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

(parameters) -> expression 
或
 (parameters) ->{ statements; }

以下是lambda表达式的重要特征:

  • 可选类型声明:不需要声明参数类型,编译器可以统一识别参数值。
  • 可选的参数圆括号:一个参数无需定义圆括号,但多个参数需要定义圆括号。
  • 可选的大括号:如果主体包含了一个语句,就不需要使用大括号。
  • 可选的返回关键字:如果主体只有一个表达式返回值则编译器会自动返回值,大括号需要指定明表达式返回了一个数值。

三、实例

public class LambdaDemo {

    public static void main(String[] args) {
        // 不需要参数,返回5
        ReturnFive m1 = () -> 5;

        // 接收一个参数,返回其2倍的值
        Multiply m2 = (num) -> 2 * num;

        // 接收两个参数,返回他们的差
        Subtract m3 = (x, y) -> x - y;

        System.out.println(m1.returnFive());
        System.out.println(m2.multiply(2));
        System.out.println(m3.subtract(4, 4));
    }

}

interface ReturnFive {
    int returnFive();
}

interface Multiply {
    int multiply(int num);
}

interface Subtract {
    int subtract(int x, int y);
}

 

四、变量的作用域

lambda 表达式只能引用标记了 final 的外层局部变量,这就是说不能在 lambda 内部修改定义在域外的局部变量,否则会编译错误。

  • 在Lambda表达式使用中,Lambda表达式外面的局部变量会被JVM隐式的编译成final类型,Lambda表达式内部只能访问,不能修改;
  • Lambda表达式内部对静态变量和成员变量是可读可写的;
public class VariableScopeDemo {
    static int a = 1;

    public static void main(String[] args) {

        VariableScope vs = (n) -> {
            a = 2;
            return a * n;
        };
        System.out.println(vs.add(2));
    }
}

interface VariableScope {
    int add(int n);
}

 

五、方法的引用

在lambda表达式中,方法引用是一种简化写法,引用的方法就是Lambda表达式的方法体的实现 。

语法:类名::方法名

方法引用一般分为三类: 

5.1静态方法引用

5.2实例方法引用

5.3构造方法引用

public class MethodRefDemo {
	public static void main(String[] args) {
		// 1、传统方式 
		Factory f = new Factory() {

			@Override
			public Parent create(String name, int age) {
				return new Boy(name, age);
			}
		};
		Parent parent = f.create("小明", 18);
		System.out.println(parent.toString());
		
		// 2、lambda表达式
		Factory f_ = Boy::new;
		Parent parent_ = f_.create("小红", 20);
		System.out.println(parent_.toString());
	}

}

@FunctionalInterface
interface Factory {
	Parent create(String name, int age);
}

class Parent {
	String name;
	int age;

	@Override
	public String toString() {
		return "Parent [name=" + name + ", age=" + age + "]";
	}
}

class Boy extends Parent {

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

 

六、stream相关操作

Lambda为java8带来了闭包,支持对集合对象的stream进行函数式操作, stream api被集成进了collection api ,允许对集合对象进行批量操作。 

Stream表示数据流,它没有数据结构,本身也不存储元素,其操作也不会改变源Stream,而是生成新Stream。作为一种操作数据的接口,它提供了过滤、排序、映射、规约等多种操作方法,这些方法按照返回类型被分为两类:凡是返回Stream类型的方法,称之为中间方法(中间操作),其余的都是完结方法(完结操作)。完结方法返回一个某种类型的值,而中间方法则返回新的Stream。 

Stream的使用过程有着固定的模式:

1.创建Stream 

2.通过中间操作,对原始Stream进行“变化”并生成新的Stream 

3.使用完结操作,生成最终结果

6.1中间操作

6.1.1过滤(filter)

结合Predicate接口,Filter对流对象中的所有元素进行过滤,该操作是一个中间操作,这意味着你可以在操作返回结果的基础上进行其他操作

	public static void main(String[] args) {
		List<String> languages = Arrays.asList("Java", "html5", "JavaScript", "C++", "hibernate", "PHP");
		
		// 开头是J的语言
		filter(languages, (name) -> name.startsWith("J"));
		// 5结尾的
		filter(languages, (name) -> name.endsWith("5"));
		// 所有的语言
		filter(languages, (name) -> true);
		// 一个都不显示
		filter(languages, (name) -> false);
		// 显示名字长度大于4
		filter(languages, (name) -> name.length() > 4);
		System.out.println("-----------------------");
		// 名字以J开头并且长度大于4的
		Predicate<String> c1 = (name) -> name.startsWith("J");
		Predicate<String> c2 = (name) -> name.length() > 4;
		filter(languages, c1.and(c2));

		// 名字不是以J开头
		Predicate<String> c3 = (name) -> name.startsWith("J");
		filter(languages, c3.negate());

		// 名字以J开头或者长度小于4的
		Predicate<String> c4 = (name) -> name.startsWith("J");
		Predicate<String> c5 = (name) -> name.length() < 4;
		filter(languages, c4.or(c5));

		// 名字为Java的
		filter(languages, Predicate.isEqual("Java"));

		// 判断俩个字符串是否相等
		boolean test = Predicate.isEqual("hello").test("world");
		System.out.println(test);
	}

	public static void filter(List<String> languages, Predicate<String> condition) {
		for (String name : languages) {
			if (condition.test(name)) {
				System.out.println("==========================");
				System.out.println(name + " ");
			}
		}
	}

6.1.2排序(sorted)

结合Comparator,该操作返回一个排序过后的流的视图,原始流的顺序不会改变。通过Comparator来指定排序规则,默认是自然排序

        List<String> list = Arrays.asList("a1", "a2", "a3", "b1", "b2", "b3");
        // 倒序
        list.stream().sorted((s1,s2)->s2.compareTo(s1)).forEach(System.out::println);
        
        // 也可以这样写
        Collections.sort(list, (String s1, String s2) -> {
            return s1.compareTo(s2);
        });
        // 简写:
        Collections.sort(list, (s1, s2) -> s1.compareTo(s2));

List<Map<String,Integer>> 根据Map.key进行排序:

    // List<Map<String,Integer>> 根据Map.key进行排序
    public static void main(String[] args) {
        List<Map<String,Integer>> list = new ArrayList<>();
        list.add(Collections.singletonMap("bily", 3));
        list.add(Collections.singletonMap("alice", 2));
        list.add(Collections.singletonMap("allen", 1));
        list.add(Collections.singletonMap("tony", 6));
        list.add(Collections.singletonMap("nice", 5));
        list.add(Collections.singletonMap("miky", 4));
        list.stream().sorted((m1, m2) -> {
            return m1.keySet().iterator().next().compareTo(m2.keySet().iterator().next());
        }).collect(Collectors.toList())
        .forEach(System.out::println);;
    }

结果展示:

Map<String,Integer> 根据key进行排序:

    // Map<String,Integer> 根据key进行排序
    public static void main(String[] args) {
        Map<String, Integer> map = new HashMap<>();
        map.put("bily", 3);
        map.put("alice", 2);
        map.put("tony", 6);
        map.put("miky", 4);
        map.entrySet().stream().sorted(Map.Entry.comparingByKey()).forEach(System.out::println);
    }

结果展示:

6.1.3映射(map)

结合Function接口,该操作能将流对象中的每一个元素映射为另一个元素,实现元素类型的转换。

public class MapedDemo {

    public static void main(String[] args) {
        List<Employee> list = new ArrayList<>();
        list.add(new Employee().builder().id(1L).empName("jack").createTime(new Date()).build());
        list.add(new Employee().builder().id(2L).empName("tom").createTime(new Date()).build());
        list.add(new Employee().builder().id(3L).empName("allen").createTime(new Date()).build());
        list.add(new Employee().builder().id(4L).empName("rock").createTime(new Date()).build());

        // 将Employee转化成SysUser
        List<SysUser> userList = list.stream().map(TranUtils::trans).collect(Collectors.toList());
        // 将list转map
        Map<Long, Employee> objMap = list.stream().collect(Collectors.toMap(Employee::getId, emp -> emp));
        // 将list转map
        Map<Long, String> strMap = list.stream().collect(Collectors.toMap(Employee::getId, Employee::getEmpName));

        // Collector.toMap另一个问题,Map中的key不能重复,如果重复的话,会抛出异常:
        // java.lang.IllegalStateException: Duplicate key The Fellowship of the Ring
        Map<Long, Employee> objMap2 = list.stream().collect(Collectors.toMap(Employee::getId, emp -> emp,(existing, replacement) -> existing));
        
        // 将List 转换 ConcurrentHashMap
        Map<Long, Employee> conMap = list.stream().collect(Collectors.toMap(Employee::getId, emp -> emp,(s1, s2) -> s1,ConcurrentHashMap::new));
    }
}

class TranUtils {
    public static SysUser trans(Employee emp) {
        return new SysUser().builder().id(emp.getId()).username(emp.getEmpName()).build();
    }
}

6.2完结操作方法

6.2.1匹配(match)

6.2.2收集(collect)

在对经过变换后,将变换的stream元素收集,比如将这些元素存在集合中,可以使用stream提供的collect方法.

6.2.3规约(reduce)

6.2.4计数(count)

6.2.4分组(groupBy)

groupBy多个属性:

	// groupBy多个属性
	private static String groupByMutilKeys(BizOrder order) {
		return order.getCustomerId() + "#" + order.getStatus();
	}

	public static void main(String[] args) throws ParseException, InterruptedException {
		List<BizOrder> orderList = new ArrayList<>();
		
		BizOrder bizOrder1 = BizOrder.builder().customerId(1L).status("SUCCESS").isValid(true).build();
		BizOrder bizOrder2 = BizOrder.builder().customerId(1L).status("SUCCESS").isValid(false).build();
		BizOrder bizOrder3 = BizOrder.builder().customerId(2L).status("FAIL").isValid(false).build();
		BizOrder bizOrder4 = BizOrder.builder().customerId(2L).status("SUCCESS").isValid(true).build();
		BizOrder bizOrder5 = BizOrder.builder().customerId(3L).status("FAIL").isValid(true).build();
		BizOrder bizOrder6 = BizOrder.builder().customerId(3L).status("FAIL").isValid(false).build();
		orderList.add(bizOrder1);
		orderList.add(bizOrder2);
		orderList.add(bizOrder3);
		orderList.add(bizOrder4);
		orderList.add(bizOrder5);
		orderList.add(bizOrder6);
		
		Map<String, List<BizOrder>> map = orderList.stream().collect(Collectors.groupingBy(o->groupByMutilKeys(o)));
		for(String key : map.keySet()) {
			System.out.println("key = " + key);
			List<BizOrder> subOrderList = map.get(key);
			System.out.println(subOrderList);
		}

6.3聚合操作

        List<Integer> list = new ArrayList<>();
        list.add(2);
        list.add(4);
        list.add(6);
        list.add(8);
        int sum = list.stream().mapToInt(i->{return i;}).sum();
        System.out.println(sum); // 输出20

 

 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值