C# vs Java:C# 五个不可替代的特性瞬间秒杀 Java 已翻译 100%

oschina 投递于 2017/08/10 14:53 (共 12 段, 翻译完成于 08-17)
阅读 2915
收藏 4
1
加载中

If we could have the best of both worlds between C# and Java, what would that look like?

The perfect programming language doesn’t exist. I hope we can agree on that, if nothing else. New languages are often developed in response to the shortcomings of another, and each is inevitably stronger in some ways and weaker in others.

C# and Java both stemmed from C/C++ languages, and they have a lot in common beyond both being Object-oriented. In addition to some structural similarities between Java’s JVM and C#’s .NET CLR, each advanced on its own path with their respective development teams focused on different visions of what the language should be.

We don’t want to get lost in the argument of which language is better than the other, we just want to outline some of the features that developers in C# are using that we don’t have available to us in Java.

Let’s get started.

已有 1 人翻译此段
我来翻译

1. LINQ

LINQ (Language-Integrated Query) was introduced to C# in 2007 to help developers query data from various sources. With it, we can write queries without needing to take into consideration the appropriate syntax for the specific database being called on. A component of LINQ, the LINQ provider, converts the query to a format that’s readable by the underlying source. For example, if we need to query data from a SQL database, the LINQ to SQL provider will convert the LINQ query into T-SQL so that the database can understand it.

To perform a query operation in LINQ, first the database is obtained, then the query is created and finally it’s executed. In LINQ to Object queries, this can be as simple as a single line of code, rather than writing complicated iterations of nested for each loops.

For example, let’s look at this code for filtering 2-digit numbers from a list in C#.

已有 1 人翻译此段
我来翻译

First, without using LINQ:

List<int> FilterTwoDigitNumbersWithoutLinq(List<int> numbers)
{
    var tens = new List<int>();
    
    for (var i=0; i < numbers.Count(); i++)
    {
        if ((9 < numbers[i]) && (numbers[i] < 100))
        {
            tens.Add(numbers[i]);
        }
    }
    
    return tens;
}

And then using LINQ in query syntax:

List<int> FilterTwoDigitNumbersWithLinq(List<int> numbers)
{
    return (from a in numbers
            where (a > 9 && a < 100)
            select a).ToList();
}

And method syntax:

List<int> FilterNonTwoDigitNumbersWithLinq2(List<int> numbers)
{
    return numbers.Where(a => a > 9 && a < 100).ToList();
}

Both syntaxes here are correct, the only real difference is that the query syntax looks more like SQL and the method syntax uses lambda expressions (and thus, looks like something we might write in Java).

Bottom Line: Many of the features that LINQ relies on, such as lambdas, are useful in their own right and already have equivalents that were implemented in Java. So, while we can use streams and lambdas for querying data, LINQ streamlines the process and removes much of the verbosity that still exists in Java.

已有 1 人翻译此段
我来翻译

2. Struct

Structs in C# are used similarly to classes. In fact, a struct can even be considered to be a “lightweight class” itself as it can contain constructors, constants, methods and more. The biggest difference between a struct and a class is that structs are value-types while classes are reference-types.

The most significant benefit of writing a struct over creating a class is that it is easier to ensure value semantics when constructing a value-type than it is when constructing a reference-type. As stated in Microsoft’s documentation, “a variable of a struct type directly contains the data of the struct, whereas a variable of a class type contains a reference to the data.” So, one of the benefits of using a struct over a class is that the only way to alter its value from other parts of the code is by explicitly passing it as a reference.

已有 1 人翻译此段
我来翻译

Developers at Microsoft recommend using a struct in place of a class only for types which are smaller than 16 bytes, are immutable, are short-lived and are not frequently boxed. Under these circumstances, using a struct may also be slightly more efficient than using a class because it will more likely be stored in the stack rather than in the heap.

Example:

public struct Point
    {
        public int X;
        public int Y;

        public Point(int X, int Y)
        {
            this.X = X;
            this.Y = Y;
        }

        public static Point operator +(Point p1, Point p2)
        {
            return new Point(p1.X + p2.X, p1.Y + p2.Y);
        }

        public override string ToString()
        {
            return ($"({X}, {Y})");
        }
    }

    class Program
    {
        static void Main(string[] args)
        {
            Point point1 = new Point(1, 5);
            Point point2 = new Point(2, 3);

            Console.WriteLine("The addition of both points will result in: {0}", (point1 + point2));

            Console.ReadKey();
        }
}

Bottom Line: In many situations, writing a struct can appear to save time on memory allocation and deallocation and, thus, be more appealing. The truth is, though, that value-types are stored wherever they are owned. Regardless of the apparent benefits or drawbacks of using structs, we don’t have to worry about any of this when it comes to Java.

已有 1 人翻译此段
我来翻译

3. Async/Await

By calling async on a code part, or more specifically on a method, that method will be executed on a separate thread so as to not block the current thread. When the code reaches the await command, it will continue running. If at that point, the async code hasn’t finished, then the execution will return to its calling method.

This can help improve the overall responsiveness of your application and help to reduce performance bottlenecks. Using asynchronous programming is very important for applications when trying to access the web and for all UI-related activities. Compared to previous techniques of implementing asynchronous programming, the use of async/await preserves the logical structure of your code and the compiler does the heavy lifting that used to be required of the developer.

已有 1 人翻译此段
我来翻译

Example:

class Program
    {
        public static void Main()
        {
            Console.WriteLine("Hey David, How much is 98745 divided by 7?");

            Task<int> david = ThinkAboutIt();

            Console.WriteLine("While he thinks, lets chat about the weather for a bit.");
            Console.WriteLine("Do you think it's going to rain tomorrow?");
            Console.WriteLine("No, I think it should be sunny.");

            david.Wait();
            var davidsAnswer = david.Result;

            Console.WriteLine($"David: {davidsAnswer}");

            Console.ReadKey();
        }

        private static async Task<int> ThinkAboutIt()
        {
            await ReadTheManual();

            Console.WriteLine("Think I got it.");

            return (98745 / 7);
        }

        private static async Task ReadTheManual()
        {
            string file = @"D:\HowToCalc.txt";

            Console.WriteLine("Reading a manual.");
            
            using (StreamReader reader = new StreamReader(file))
            {
                string text = await reader.ReadToEndAsync();
            }

            Console.WriteLine("Done.");
        }
}

The output:

// Possible Output:

Hey David, How much is 98745 divided by 7?
Reading a manual.
While he thinks, lets chat about the weather for a bit.
Do you think it's going to rain tomorrow?
No, I think it should be sunny.
Done.
Think I got it.
David: 14106

Bottom line: CompletableFutures undoubtedly brought us closer to having equivalent capabilities in asynchronous programming in C# and Java. Still, the complicated nature of using it makes it no match for the ease with which the async/await keywords can be implemented.

已有 1 人翻译此段
我来翻译

4. Lazy<T> Class

Whether working in C# or in Java, many of us have implemented lazy initialization (or instantiation) so that an object is not created until the first time that it will be used. One of the more common instances that lazy initialization is used for is when an application loads many objects upon launching but only requires a few of them initially. In this case, we want to instruct unnecessary objects to initialize only when needed to improve the performance of our application.

Bottom Line: Implementing lazy initialization recently became much easier in Java (as did many other things) when lambda expressions were introduced in Java 8. Still, in C# we can use the Lazy<T> wrapper class which provides the semantics of lazy initialization for any class library or user-specified type.

已有 1 人翻译此段
我来翻译

5. Some Keyword Equivalencies

Useful features in languages don’t have to be as big of an undertaking as implementing something like LINQ in C# or modules in Java. Here are some keywords that help C# developers that we don’t have in Java:

a. as

The as keyword in C# attempts to safe-cast an object to a type, and if it can’t it returns null. Java’s instanceof is almost comparable, but it is a boolean that returns true if the types match and false if they don’t.

已有 1 人翻译此段
我来翻译

b. Yield

Yield and return yield are used in C# to perform custom and stateful iterations without an explicit extra class and without the need to create a temporary collection. Our best options for implementing iterations in Java seem to be accessing an external library or using lambdas which were introduced in Java 8.

c. var

Var is an implicit type that is determined by the compiler and is functionally equivalent to writing an explicit type (i.e. int, string, etc.). Aside from saving a few extra keystrokes, var allows for anonymous types which are most typically used in LINQ queries. We’re expecting to see a “var” identifier implemented in the highly anticipated Java SE 9 which will “extend type inference to declarations of local variables with initializers.”

已有 1 人翻译此段
我来翻译
本文中的所有译文仅用于学习和交流目的,转载请务必注明文章译者、出处、和本文链接。
我们的翻译工作遵照 CC 协议,如果我们的工作有侵犯到您的权益,请及时联系我们。
加载中

评论(2)

I
Indifer
论语言设计,C#绝对是一个非常棒的语言
啦啦啦拉拉
啦啦啦拉拉
linq厉害啊,看来C#不需要用ORM
返回顶部
顶部