jdk 1.8 新特性 之 Stream Lambda表达式 (一)

初识表达式

本次项目搭建为Maven项目 jdk 为1.8 ,当然用 普通的java 项目也可以。
在这里插入图片描述

这段时间看虚拟机介绍的时候发现1.8 有一个函数编程,然后看到说函数编程是一个高级编程(也有可能是开玩笑的)就觉得应该挺好用的,然后就查阅资料,看到了函数编程的第一步就是 要会用 lambad 表达式。

1.第一次使用 lambda 表达式

看到网上有个例子说是用lambda 实现了一个按钮的监听事件,我觉得这个例子很好,为了能够理解这个例子我还特意从网上查阅了一下资料。我直接贴代码吧。

这个是窗体类

import javax.swing.SwingUtilities;

import swing.swing.window.IndexFrame;

/**
 * Hello world!
 *
 */
public class App {
	public static void main(String[] args) {
		
		javax.swing.SwingUtilities.invokeLater(new Runnable() {
            public void run() {
            	// 用java 默认的窗口模式,不设置就是 用系统自带的
            	//JFrame.setDefaultLookAndFeelDecorated(true);
            	IndexFrame index = new IndexFrame(500, 500, "你好世界");
            	index.show();
            }
        });
		 
		// lambda 表达式形式
		SwingUtilities.invokeLater(() -> {
			IndexFrame index = new IndexFrame(500, 500, "你好世界");
        	index.show();
		});
		
		// 
		Runnable runnable1 = () -> {
			IndexFrame index = new IndexFrame(500, 500, "你好世界");
        	index.show();
		};
		SwingUtilities.invokeLater(runnable1);
		
	}
}

这里绑定事件的时候 传递的是 参数 -> 结果
接下来是启动类

package swing.swing;

import javax.swing.SwingUtilities;

import swing.swing.window.IndexFrame;

/**
 * Hello world!
 *
 */
public class App {
	public static void main(String[] args) {
		
		javax.swing.SwingUtilities.invokeLater(new Runnable() {
            public void run() {
            	// 用java 默认的窗口模式,不设置就是 用系统自带的
            	//JFrame.setDefaultLookAndFeelDecorated(true);
            	IndexFrame index = new IndexFrame(500, 500, "你好世界");
            	index.show();
            }
        });
		
		// 现在先不用管,只是先贴出来,后边会详细说明
		// lambda 表达式形式
		SwingUtilities.invokeLater(() -> {
			IndexFrame index = new IndexFrame(500, 500, "你好世界");
        	index.show();
		});
		
		// 
		Runnable runnable1 = () -> {
			IndexFrame index = new IndexFrame(500, 500, "你好世界");
        	index.show();
		};
		SwingUtilities.invokeLater(runnable1);
		
	}
}

可以看到控制台每次单机按钮都会打印两次绑定的单击事件,现在完成了 Lambda 的初次使用,接下来了解一下怎么正确使用吧。

2.如何辨别 Lambda 表达式 (待补充)

首先看到第一个lambda 表达式以后先用一下,我们知道list 排序的时候需要实现一个Comparator 接口的compare 方法。代码如下

		List<Integer> list = new ArrayList<Integer>() {{add(1);add(2);add(4);add(3);}};
		
		list.sort(new Comparator<Integer>() {
			@Override
			public int compare(Integer o1, Integer o2) {
				// TODO Auto-generated method stub
				return o1-o2;
			}
		});
		System.out.println(list);
		
		list.sort((o1,o2) -> o2-o1);
		System.out.println(list);

执行结果
在这里插入图片描述
可以看到 lambda 表达式很轻松的就重写了这个方法。个人理解,他可以去轻松的重写任何一个要重写的方法,(通俗点就是 用这个重写类的某一个方法实现这个功能,仅仅重写这一个方法的时候,多个方法的时候他可能会找不到要重写的方法,毕竟他也是代码写出来的,不会那么只能,目前没有很好的例子,以后有例子了我再补充上去,)

进入正题:
lambda 的几种表现形式:

	// 重写现成启动的时候的run方法, 这个是不带参数的
	Runnable noArguments = () -> System.out.println("Hello World");
	// 重写的时候方法体不值一行的时候 如果有返回值  加return 
	Runnable noArgumentss = () ->{
		System.out.println("Hello World");
		System.out.println("Hello World");
		// 方法有返回值的时候
		// return "";
	}
	// 还有就是刚才绑定单击事件的时候,只有一个参数的 可以省略 ()
	ActionListener oneArgument = event -> System.out.println("button clicked");
	// 顺便提到,如果只有一行代码,并且是返回值的结果  就比如说重写了一个方法  直接就是  return a; 可以这样写
	//  BinaryOperator<T> 这个是jdk 1.8 提供的储存函数的 类 可以存放函数并且定义返回值
	BinaryOperator<Long> add = (x, y) -> x + y; ?
	BinaryOperator<Long> addExplicit = (Long x, Long y) -> x + y;

下面看一下这个 1.8 提供的这个函数类 BinaryOperator 怎么使用

		BinaryOperator<Integer> add = new BinaryOperator<Integer>() {
			@Override
			public Integer apply(Integer t, Integer u) {
				Integer n1 = Integer.parseInt(t.toString());
				Integer n2 = Integer.parseInt(u.toString());
				System.out.println("  n1+n2="+ (n1+n2));
				return (n1+n2);
			}
		};
		// lambda 自己推断类型
		BinaryOperator<Integer> add1 = (n1,n2) ->{
			System.out.println("1: n1+n2="+ (n1+n2));
			return (n1+n2);
		};
		// 显示声明类型
		BinaryOperator<Integer> add2 = (Integer n1,Integer n2) ->{
			System.out.println("2: n1+n2="+ (n1+n2));
			return (n1+n2);
		};
		
		add.apply(1, 2);
		add1.apply(1, 2);
		add2.apply(1, 2);

代码的执行结果为:
在这里插入图片描述

可以看出来 用了 lambda 表达式是多么的方便。

3.流

Stream 是java 1.8 新引入的抽象操作集合的类
之前我们统计一个县的同名人数,要写一个循环,然后遍历这个循环,求count

		List<String> countyNames = new ArrayList<String>(){{
			add("张三");add("李四");add("李四");
			add("李四");add("张三");add("王五");
			add("王五四");add("李四");add("张四");
			add("张三");add("王五");add("王五");
			add("李四");add("张四");add("王五");
			add("aa");add("bb");add("cc");
			add("aa");add("bb");add("cc");
			add("aa");add("bb");add("cc");
		}};
		int count = 0;
		for(String str : countyNames) {
			if(str.trim().indexOf("张") != -1)
				count ++;
		}
		System.out.println("姓张的个数为:"+count);

最后的结果是 5
但是 用 Stream 就可以减少很多代码

	// stream  筛选
	Long count1 = countyNames.stream()
		.filter(str -> str.trim().indexOf("张") != -1)
		.filter(str -> str.trim().equals("张四"))
		.count();
	System.out.println("stream: 筛选的结果:"+count1);

这样就不仅少了很多代码,代码结构也变得更容易理解。
感兴趣的人可以去看一下他们的源码。大致就是用一个迭代器去实现的

上面的式子用了两个筛选,这样并不会造成循环两次的性能浪费,因为 filter 是一个惰性方法,
后面的 count 方法被称为 及早求值 方法

顾名思义,惰性求职方法 就是不会产生新集合,及早求值方法就是会产生结果的方法,怎么区分它们呢,

如果返回值是 Stream ,那么是惰性求值;
如果返回值是另一个值或为空,那么就是及早求值

看一段代码

		countyNames.stream().filter(str -> {
			System.out.println("我是惰性方法");
			return true;
		});
		
		countyNames.stream().filter(str -> {
			System.out.println("我是调用了及早求值所以我执行了");
			return true;
		}).count();

在这里插入图片描述
可以看到程序并没有走惰性方法,根本就没执行,只有他碰到求值方法才会返回。不得不佩服jdk 的开发人员的头脑。

4.流的常用操作

看一段代码

		List<String> newNames = countyNames.stream()
				.map(str -> str+ "1")
				.collect(Collectors.toList());
		System.out.println(newNames.toString());

想必看到这个代码就已经大概知道这个代码的用处了,他们的运行结果是:
在这里插入图片描述
这就是接下来要说的 map 方法 和 toList 方法

我们经常在写代码的时候要给某一些 集合 元素做一些修改这时候就用到map方法来操作数据的元素,看到我这里是给他拼接了一个 1
方法内部的 lambda 表达式收到一个 参数 对应集合类型,返回的也是集合类型,这里要注意一下。

min max

		Optional<Integer> opt1 = list.stream()
				.min(Comparator.comparing(number -> number));
		// 这个是根据 字符串的长度找最大了,也可以返回string 类型的按照字典排序
		Optional<String> opt = countyNames.stream()
				.max(Comparator.comparing(str -> str.toString().length()));
		System.out.println(opt.get()+ "\n" +opt1.get());

5. reduce

进行自定义计算两个之间的值,可用于数字

		// 计算数字的和 ,这个是计算的总和
		System.out.println(
			list.stream()
				.reduce(-10,(n1,n2)-> n1+n2)
		);
		// 拼接全部的字符
		System.out.println(
			countyNames.stream()
				.reduce("names :   ", (n1,n2)->n1+n2)
		);

在这里插入图片描述

6. flatMap

我把这个单独列出来是因为他跟之前的不一样,看代码

		List<Integer> list3 = Stream.of(
				new ArrayList<Integer>() {{add(1);add(2);}},
				new ArrayList<Integer>() {{add(3);add(4);}})
				.flatMap(numbers -> numbers.stream())
				.collect(Collectors.toList());
		System.out.println(list3.toString());

这里我是用 Stream 生成了两个 集合的stream 然后调用 这个 flatMap 方法,该方法仅限于多个列表的流, 把多个列表拼接到一起。

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值