前言:

笔者的实习使用.NET环境而之前在学校给培训的是Java,
所以目前经常在两种语言和平台中切换,
由于工作中使用C#,学到了很多C#的知识和框架,它们或多或少和Java中有的东西有相似性.
从中也有一些启发,故将之记录下来

背景:
C#的Linq最早发布于2007年的C#3.0
而Java的流操作到Java8标准才出现

两者的使用目的都是为了简化或提高对集合类型(广义的IEumnable对象)的操作,提高效率.
且都被实践证明是非常重要的.
理解和掌握他们的使用对自己的编程思想是一次大的提升
接下来是具体的使用

Java的流操作

Java的流操作主要操作集合类型(当然也可以是数组),方式分为并行操作和串行操作(并行操作涉及多线程进行)
这里举一个简单的例子

public class StreamTest {
	//初始化一个简单的字符串集合
	private static List<String> list;
	
	static {
		list = new ArrayList<>();
		list.add("GTX1060");
		list.add("GTX1070");
		list.add("6800XT");
		list.add("RTX3090");
		list.add("RTX3060");
		list.add("6500XT");
		list.add("HD7850");
	}
	
	public static void main(String[] args) {
		//利用简单的Filter过滤,以下两种方法都能够把N卡从集合中挑选出来
		
		List<String> fuckNvidia = list.stream()
				.filter(item->!item.endsWith("XT")&&!item.startsWith("HD")).toList();
		
		List<String> fuckNvidia2 = list.stream()
				.filter(item->item.startsWith("GTX")||item.startsWith("RTX")).toList();
		
		fuckNvidia.forEach(item->System.out.println(item));
		//结果
		//GTX1060
		//GTX1070
		//RTX3090
		//RTX3060

		//map方法以便利处理集合中每一个元素,将其变成小写
		//这里要理解什么是Function<T,R>,Predicate<T>,在Java中,它们是动态的接口
		//在C#中它们是函数委托可以直接赋值匹配的方法,这里有一个区别就是C#的Function可以无限的塞参数,像Funaction<T,T,T,T,...,R>而Java不行,BiFunction也只能输入两个参数,并不是很自由
		List<String> lower = list.stream().map((item)-> {return 	item.toLowerCase();}).toList();
		
		lower.forEach(item->System.out.println(item));
		//结果:
		//gtx1060
		//gtx1070
		//6800xt
		//rtx3090
		//rtx3060
		//6500xt
		//hd7850
		
	}

}

再来个稍微复杂点的例子

public class StreamPlusTest {
	
	private static List<Person> personlist;
	
	static {
		personlist = new ArrayList<Person>();
		personlist.add(new Person("黄仁勋", "呆湾省", 50, "屑"));
		personlist.add(new Person("拿破仑", "科西嘉", 250, "FRA"));
		personlist.add(new Person("弗朗茨", "维也纳", 270, "HRE"));
		personlist.add(new Person("达武", "法兰西", 255, "FRA"));
		personlist.add(new Person("腓特烈", "柏林", 255, "HRE"));
	}
	//这次来操作对象集合
	public static class Person{
		private String name;
		private String hometown;
		private int age;
		private String Work;
		public Person() {
		}
		public Person(String name, String hometown, int age, String work) {
			this.name = name;
			this.hometown = hometown;
			this.age = age;
			Work = work;
		}
		
		public String getName() {
			return name;
		}
		public void setName(String name) {
			this.name = name;
		}
		public String getHometown() {
			return hometown;
		}
		public void setHometown(String hometown) {
			this.hometown = hometown;
		}
		public int getAge() {
			return age;
		}
		public void setAge(int age) {
			this.age = age;
		}
		public String getWork() {
			return Work;
		}
		public void setWork(String work) {
			Work = work;
		}
		@Override
		public String toString() {
			return "Person [name=" + name + ", hometown=" + hometown + ", age=" + age + ", Work=" + Work + "]";
		}
		
		
	}
	
	public static void main(String[] args) {
		//根据实体的某个属性赛选集合内容
		List<Person> list = personlist.stream().filter(person->person.getWork().equals("FRA")).toList();
		list.forEach(item->System.out.println(item));
		//得到如下输出
		//Person [name=拿破仑, hometown=科西嘉, age=250, Work=FRA]
		//Person [name=达武, hometown=法兰西, age=255, Work=FRA]
		
		//根据某个属性的值对集合进行排序
		List<Person> sorted_list = personlist.stream()
				.sorted((left,right)->left.getAge()>right.getAge()? 1:-1).toList();
		
		sorted_list.forEach(item->System.out.println(item));
		 //进行reduce计算,返回计算结果,PS:不要对reduce名字的意思迷惑,它确实负责进行计算,并非字面上的减少/减轻的含义
		 //这里需要注意这个BinaryOperator,它是二元运算符的意思,它在这里负责制定运算的规则
		 Optional<Person> p1 =  personlist.stream().reduce(new BinaryOperator<StreamPlusTest.Person>() {
			
			@Override
			public Person apply(Person t, Person u) {
				Person temp = new Person();
				temp.setAge(t.getAge()+u.getAge());
				return temp ;
			}
		});
		
		 System.out.println(p1.get());
		 //输出累计年龄值1080
		
	}

}

stream操作确实有一定的难度,尤其是涉及并行的计算,还有方法执行的嵌套.

C#的LINQ操作

linq的语法很像Sql,如果你熟悉Sql的话上手并不是很难
并且,它的拓展性也很好,可以被转义成sql执行,配合EF也使ORM的操作变得简单
这里以和上例一样的数据进行举例

class Program
    {
        private static List<string> list;

        public static List<string> ListINIT()
        {
            return  new List<string>()
            {
                "GTX1060",
                "GTX1070",
                "6800XT",
                "RTX3090",
                "RTX3060",
                "6500XT",
                "HD7850"
            };

        }
        static void Main(string[] args)
        {
            list = ListINIT();
            
			//LINQ可以使用两种查询模式,它们差别比较大,但效果是一样的,你可以任选其一
	
			//1.方法调用方式
            List<string> list1 = list.Where(item=>item.StartsWith("GTX")||item.StartsWith("RTX")).ToList();
			//查询语句方式
            List<string> list2 = (from item in list where item.StartsWith("RTX") || item.StartsWith("GTX") select item).ToList();
			
           

			//可以用select方法对集合内的数据进行操作,但这不是这要用途,主要用途是用于圈定一个自己指定返回类型
			//这个在之后的用例中将会讲到
            List<string> list3 =  list.Select(item => item = item.ToLower()).ToList();
        }
    }

这里这个Where就和Java的Stream中的filter一样,也对集合进行了过滤的操作
当然,LINQ也可以进行集合数据的操作,

为了对比,再将上面的例子放入C#中

public class Person
{
    public string name { get; set; }

    public string hometown { get; set; }
    public int age { get; set; }

    public string work { get; set; }

    public Person(string name, string hometown, int age, string work)
    {
        this.name = name;
        this.hometown = hometown;
        this.age = age;
        this.work = work;
    }

    public override string ToString()
    {
        return "Person["+name+","+hometown+","+age+","+work+"]";
    }
    

}
   

class Program
{
    

    public static List<Person> ListInitTwo()
    {
        return new List<Person>() {
            new Person("黄仁勋", "呆湾省", 50, "屑"),
            new Person("拿破仑", "科西嘉", 250, "FRA"),
            new Person("弗朗茨", "维也纳", 270, "HRE"),
            new Person("达武", "法兰西", 255, "FRA"),
            new Person("腓特烈", "柏林", 255, "HRE")

        };
    }

    public static int CompareByAge(Person x, Person y)
    {
        return x.age > y.age ? 1 : -1;
    }
    static void Main(string[] args)
    {
        

        List<Person> list = ListInitTwo();
		//同样可以通过Where进行过滤集合
        List<Person> list2 = list.Where(item => item.work.StartsWith("FRA")).ToList();
		//可以使用委托来进行排序,
        //list.Sort(CompareByAge);
        //也可以通过lambda进行排序,实现方法都是实现IComparer这个比较借口,这个IComparable和IComparer借口和Java的设计一模一样,有兴趣可以深入了解一下
        list.Sort((x, y) => { return x.age > y.age ? 1 : -1; });
        list.ForEach(item => Console.WriteLine(item));
        
         //可以调用这个aggregate进行计算,和stream操作的reduce差不多,这个地方也是比较复杂的,需要深入的思考,这里只做一个小的演示
         var result = list.Aggregate((x,y)=>{ 
                                                    Person temp = new Person();
                temp.age = x.age + y.age;
                return temp;
            });

            Console.WriteLine("合計的年齡為"+result);
    }
}