In addition to Weibo, there is also WeChat
Please pay attention
WeChat public account
Shulou
2025-04-01 Update From: SLTechnology News&Howtos shulou NAV: SLTechnology News&Howtos > Development >
Share
Shulou(Shulou.com)06/02 Report--
This article mainly introduces from Java into Scala how to use tuples, arrays and lists, has a certain reference value, interested friends can refer to, I hope you can learn a lot after reading this article, the following let Xiaobian take you to understand.
Use Option (s)
Under what circumstances, "nothing" does not mean "nothing"? What does it have to do with null when it is zero?
It is very difficult to express as "nothing" in software for a concept that most of us are very familiar with. For example, look at the heated discussion about NULL and 0 in the C++ community, or the debate over the NULL column value in the SQL community. NULL or null means "nothing" to most programmers, but this raises some special problems in the Java language.
Consider a simple operation that looks up the programmer's salary from some database located in memory or on disk: API allows the caller to pass in a String containing the programmer's name, what does that return? From a modeling perspective, it should return an Int that represents the programmer's annual salary; but there is a problem if the programmer is not in the database (she may not have been hired at all, or has been fired, or has typed the wrong name... So what should be returned If the return type is Int, you cannot return null. This "flag" usually indicates that the user was not found in the database. (you might think that an exception should be thrown, but most of the time the lost value in the database should not be regarded as an exception, so you should not throw an exception here.)
In the Java code, we finally mark the method to return java.lang.Integer, which forces the caller to know that the method can return null. Naturally, we can rely on the programmer to fully document the scenario, and we can also rely on the programmer to read carefully prepared documentation. This is similar to: we can ask the manager to listen to our objection to their request for an impossible project deadline, and then the manager can further communicate our objection to the boss and users.
Scala provides a common functional approach to break this deadlock. In some ways, the Option type or Option [T] does not attach importance to description. It is a generic class with two subclasses, Some [T] and None, to represent the possibility of "no value" without requiring the language type system to take great pains to support this concept. In fact, using the Option [T] type can make the problem clearer (which will be used in the next section).
When using Option [T], the key point is to realize that it is essentially a strongly typed collection of size "1" and the possibility of using a different value None to represent the "nothing" value. Therefore, instead of returning null here to indicate that no data was found, the method is declared to return Option [T], where T is the original type returned. Then, for scenarios where no data is found, simply return None, as shown below:
Listing 1. Are you ready to play football?
Test def simpleOptionTest = {val footballTeamsAFCEast = Map ("New England"-> "Patriots", "New York"-> "Jets", "Buffalo"-> "Bills", "Miami"-> "Dolphins", "Los Angeles"-> null) assertEquals (footballTeamsAFCEast.get ("Miami"), Some ("Dolphins") assertEquals (footballTeamsAFCEast.get ("Miami"). Get () "Dolphins") assertEquals (footballTeamsAFCEast.get ("Los Angeles"), Some (null)) assertEquals (footballTeamsAFCEast.get ("Sacramento"), None)}
Note that the return value of get in Scala Map does not actually correspond to the passed key. Instead, it is an instance of Option [T], which can be Some () or None associated with a value, so it is clear that the key was not found in map. This is especially important if it can indicate that a key exists on the map but has a corresponding null value. For example, the Los Angeles key in listing 1.
In general, programmers use pattern matching when dealing with Option [T], a very functional concept that allows types and / or values to be effectively "enabled", not to mention binding values to variables in the definition, switching between Some () and None, and extracting the value of Some (without calling the cumbersome get () method). Listing 2 shows Scala's pattern matching:
Listing 2. Ingenious pattern matching
Test def optionWithPM = {val footballTeamsAFCEast = Map ("New England"-> "Patriots", "New York"-> "Jets", "Buffalo"-> "Bills" "Miami"-> "Dolphins") def show (value: Option [String]) = {value match {case Some (x) = > x case None = > "No team found"}} assertEquals (show (footballTeamsAFCEast.get ("Miami")), "Dolphins")}
C # 2.0 can be changed to the type of null value
Other languages have tried to solve the problem of "null valueability" in various ways: C++ ignored this problem until it was finally determined that null and 0 were different values. The Java language still does not completely solve this problem, but relies on autoboxing (autobox)-automatically converting primitive types to their wrapper objects (introduced after 1.1)-to help Java programmers solve the problem. Some pattern aficionados suggest that each type should have a corresponding "Null Object", rewriting all its methods into instances of types (actually subtypes) that do nothing-which turns out to be a lot of work. After the release of C # 1.0, the C # designer decided to take a completely different approach to the problem of null valuing.
C # 2.0 introduces the concept of types that can be changed into null values, but it is important to add syntax support that any specific value type (basically a primitive type) can be encapsulated into a generic / template class Nullable by encapsulating null
< T>To provide null support Nullable
< T>Itself is passed in the type declaration? The modifier symbol is introduced. So, int? Represents an integer that may also be null.
On the face of it, this seems reasonable, but things soon become complicated. Int and int? Should it be considered a compatible type, and if so, when will int be promoted to int?, and vice versa? When adding int to int? What will happen? will it turn out to be null? This kind of problem and so on. The type system then made some important adjustments, and the types that could be changed into null values were then included in 2. 0-and the C # programmer almost completely ignored them.
Review the functional method of type Option, which makes the boundary between Option [T] and Int clear and looks simpler than other methods. This is especially true when comparing counterintuitive (counterintuitive) promotion rules that can be changed into null value types. It is worthwhile to think about this problem in the functional field for nearly two decades. It takes some effort to use Option [T], but overall, it produces clearer code and expectations.
Tuples and collections
In C++, we call it a structure. In Java programming, we call it a data transfer object or a parameter object. In Scala, we call it a tuple. In essence, they are classes that collect other data types into a single instance and do not use encapsulation or abstraction-in fact, it is often more useful not to use any abstraction.
Creating a tuple type in Scala is very simple, it's only part of the body: if you expose elements to the outside first, it's worthless to create names inside the type that describe those elements. Consider listing 3:
Listing 3. Tuples.scala
/ / JUnit test suite / / class TupleTest {import org.junit._, Assert._ import java.util.Date @ Test def simpleTuples () = {val tedsStartingDateWithScala = Date.parse ("3 Ted", "Scala", tedsStartingDateWithScala) assertEquals (tuple._1, "Ted") assertEquals (tuple._2, "Scala") assertEquals (tuple._3, tedsStartingDateWithScala)}}
Creating tuples is as simple as placing values in a set of parentheses as if you were calling a method call. To extract these values, you only need to call the "_ n" method, where n represents the positional parameters of the relevant tuple elements: _ 1 for the first bit, _ 2 for the second bit, and so on. The traditional Java java.util.Map is essentially a collection of tuples divided into two parts.
Tuples can easily move multiple values using a single entity, which means that tuples can provide a very heavyweight operation in Java programming: multiple return values. For example, a method can count the number of characters in String and return the characters that appear the most in that String, but if the programmer wants to return both the most common character and the number of times it occurs, then the programming is a bit complicated: either create an explicit class that contains the character and the number of occurrences, or save the value as a field in the object and return the field value if needed. No matter which method you use, you need to write a lot of code compared to using Scala; by simply returning tuples containing characters and their occurrences, Scala can not only easily use "_ 1", "_ 2", and so on to access individual values of tuples, but also easily return multiple return values.
As shown in the following section, Scala frequently saves Option and tuples to collections (such as Array [T] or lists), providing great flexibility and power through a relatively simple structure.
The array takes you out of the haze.
Let's take a fresh look at an old friend-the array-which in Scala is Array [T]. Like the array in Java code, Scala's Array [T] is an ordered sequence of elements indexed by a numeric value that represents the location of the array, and the value cannot exceed the total size of the array, as shown in listing 4:
Listing 4. Array.scala
Object ArrayExample1 {def main (args: Array [String]): Unit = {for (I System.out.println (arg))}}
You don't seem to save much work, but passing a function (anonymous or otherwise) into another class to gain the ability to execute in specific semantics (in this case, traversing arrays) is a common theme of functional programming. The use of higher-order functions in this way is not limited to iterations; in fact, you often have to filter the contents of the array to remove useless content and then process the results. For example, in Scala, you can easily filter using the filter method, then get the list of results and use map and another function of type (T) = > U, where T and U are both generic types, or foreach to process each element. I took the latter approach in listing 6 (notice that filter uses a (T): Boolean method, which means using any type of parameter held by the array and returning a Boolean).
Listing 6. Find all Scala programmers
Class ArrayTest {import org.junit._, Assert._ @ Test def testFilter = {val programmers = Array (new Person ("Ted", "Neward", 37, 50000, Array ("C++", "Java", "Scala", "Groovy", "C #", "F#", "Ruby")), new Person ("Amanda", "Laucher", 27, 45000 Array ("C#", "F#", "Java", "Scala"), new Person ("Luke", "Hoban", 32, 45000, Array ("C#", "Visual Basic", "F#")), new Person ("Scott", "Davis", 40, 50000, Array ("Java") "Groovy")) / / find all Scala programmers... Val scalaProgs = programmers.filter ((p) = > p.skills.contains ("Scala")) / / there should be only 2 assertEquals (2, scalaProgs.length) / /. Now perform an operation on each programmer in the resulting / / array of Scala programmers (give them a raise, of course!) / / scalaProgs.foreach ((p) = > p.salary + = 5000) / / Should each be increased by 5000. AssertEquals (programmers (0). Salary, 50000 + 5000) assertEquals (programmers (1). Salary, 45000 + 5000) / /. Except for our programmers who don't know Scala assertEquals (programmers (2). Salary, 45000) assertEquals (programmers (3). Salary, 50000)}}
The map function is used to create a new Array, leaving the original array contents unchanged, which is actually preferred by most functional programmers:
Listing 7. Filter and map
Test def testFilterAndMap = {val programmers = Array (new Person ("Ted", "Neward", 37, 50000, Array ("C++", "Java", "Scala", "C#", "F#", "Ruby"), new Person ("Amanda", "Laucher", 27, 45000, Array ("C#", "F#", "Java", "Scala") New Person ("Luke", "Hoban", 32, 45000, Array ("C #", "Visual Basic", "F#")) new Person ("Scott", "Davis", 40, 50000, Array ("Java", "Groovy") / / Find all the Scala programmers. Val scalaProgs = programmers.filter ((p) = > p.skills.contains ("Scala")) / / Should only be 2 assertEquals (2, scalaProgs.length) / /. Now perform an operation on each programmer in the resulting / / array of Scala programmers (give them a raise, of course!) / / def raiseTheScalaProgrammer (p: Person) = {new Person (p.firstName, p.lastName, p.age, p.salary + 5000, p.skills)} val raisedScalaProgs = scalaProgs.map (raiseTheScalaProgrammer) assertEquals (2, raisedScalaProgs.length) assertEquals (50000 + 5000, raisedScalaProgs (0) .minutes) assertEquals (45000 + 5000) RaisedScalaProgs (1) .clients)}
Note that in listing 7, the salary member of Person can be marked as "val", indicating that it cannot be modified, rather than "var" in order to modify the salaries of different programmers as above.
Scala's Array provides a number of methods that cannot be listed and demonstrated here. In general, when using arrays, you should make full use of the methods provided by Array instead of using the traditional for. Mode traverses the array and finds or performs the required operations. The easiest way to implement this is usually to write a function (using nesting if necessary, as shown in the testFilterAndMap example in listing 7) that performs the desired operation and then passes the function to one of the map, filter, foreach, or other methods in Array based on the desired result.
Functional list
One of the core features of functional programming for many years is the list, which enjoys the same level of "built-in" nature in the object domain as arrays. Lists are critical to building functional software, so you (as a fledgling Scala programmer) must be able to understand lists and how they work. Even though lists never form a new design, Scala code widely uses lists in its libraries. Therefore, the study list is very necessary.
In Scala, a list is similar to an array because its core definition is the standard class List [T] in the Scala library. And, like Array [T], List [T] inherits many base classes and features, first using Seq [T] as the direct upper base class.
Basically, a list is a collection of elements that can be extracted through the header or footer of the list. The list comes from Lisp, a language that revolves around "LISt processing", which gets the head of the list through the car operation and the tail of the list through the cdr operation (the name origin is history-related; the first person who can explain it is rewarded).
In many ways, using lists is easier than using arrays for two reasons: first, functional languages have always provided good support for list processing in the past (which Scala inherits), and second, lists can be well constructed and decomposed. For example, a function usually selects content from a list. To do this, it selects the first element of the list-the list header-to perform processing on that element, and then recursively passes the rest of the list to itself. This greatly reduces the possibility of having the same shared state within the processing code, and if only one element needs to be processed in each step, it is highly likely that the code will be distributed across multiple threads (if the processing is good).
Composing and decomposing lists is very simple, as shown in listing 8:
Listing 8. Use list
Class ListTest {import org.junit._, Assert._ @ Test def simpleList = {val myFirstList = List ("Ted", "Amanda", "Luke") assertEquals (myFirstList.isEmpty, false) assertEquals (myFirstList.head, "Ted") assertEquals (myFirstList.tail, List ("Amanda", "Luke") assertEquals (myFirstList.last, "Luke")}}
Note that building a list is very similar to building an array; both are similar to building a normal object, except that there is no need for "new" (this is the functionality of the "case class", which we will cover in a future article). Note further the result of the tail method call-the result is not the last element of the list (provided through last), but the list elements other than the first.
Of course, part of the power of lists comes from the ability to recursively process list elements, which means that you can extract headers from the list until the list is empty, and then accumulate the results:
Listing 9. Recursive processing
Test def recurseList = {val myVIPList = List ("Ted", "Amanda", "Luke", "Don", "Martin") def count (VIPs: List [String]): Int = {if (VIPs.isEmpty) 0 else count (VIPs.tail) + 1} assertEquals (count (myVIPList), myVIPList.length)}
Note that there is a bit of a hassle if you ignore the return type count,Scala compiler or interpreter-because this is a tail-recursive call designed to reduce the number of stack frames created in a large number of recursive operations, so you need to specify its return type. Even so, you can easily use the "length" member of List to get the number of list items, but the key is how to explain the power of list processing. The entire method in listing 9 is completely thread-safe because the entire intermediate state used in list processing is saved on the stack of parameters. Therefore, by definition, it cannot be accessed by multiple threads. One of the advantages of a functional approach is that it is actually quite different from the function of the program and still creates a shared state.
List API
Lists have other interesting features, such as an alternative to building lists, using the:: method (yes, this is one method. It's just that the name is interesting. Therefore, instead of using the "List" constructor syntax to build lists, you "splice" them together (when calling the:: method), as shown in listing 10:
Listing 10. Is it C++?
Test def recurseConsedList = {val myVIPList = "Ted":: "Amanda":: "Luke": "Don":: "Martin":: Nil def count (VIPs: List [String]): Int = {if (VIPs.isEmpty) 0 else count (VIPs.tail) + 1} assertEquals (count (myVIPList), myVIPList.length)}
Be careful when using the:: method-it introduces some interesting rules. Its syntax is very common in functional languages, so the creators of Scala chose to support it, but to use it correctly and universally, you must use an odd rule: any "wacky method" ending with a colon is right-associative, which means that the entire expression starts with its rightmost Nil, which happens to be a List. Therefore, you can think of:: as a global:: method, as opposed to a member method of String (used in this case); this in turn means that you can build a list of everything. When using::, the rightmost element must be a list, or you will get an error message.
What is a right correlation?
To better understand: methods, keep in mind that operators such as "colons" are just interesting methods with names. For normal left management syntax, the tag on the left is usually the object on which I'm going to call the method name (the tag on the right). Therefore, in general, the expression 1 + 2 is equivalent to 1 + (2) in the eyes of the compiler.
But none of this is appropriate for lists-every class in the system needs to use the:: method for all types in the system, which seriously violates the principle of separation of concerns.
The fix for Scala is that any method with a strange name that ends with a colon (for example:: or:, or even a method I created myself, such as foo:) is associated to the right. So, for example, a:: B:: C:: Nil is converted to Nil.:: (c. List: (a)), which is exactly what I need: List in the first place, so that each call:: can get the object parameter and return a List, and continue to execute.
It is best to specify the right association attribute for other naming conventions, but as of this writing, Scala has hard-coded this rule into the language. For now, the colon is the only character that triggers the right association behavior.
One of the most powerful uses of lists in Scala is in combination with pattern matching. Because a list can not only match types and values, it can also bind variables at the same time. For example, I can simplify the list code in listing 10 by using pattern matching to distinguish between a list with at least one element and an empty list:
Listing 11. Use pattern matching and lists together
Test def recurseWithPM = {val myVIPList = "Ted":: "Amanda":: "Luke":: "Don":: "Martin":: Nil def count (VIPs: List [String]): Int = {VIPs match {case h:: t = > count (t) + 1 case Nil = > 0}} assertEquals (count (myVIPList), myVIPList.length)}
In the first case expression, the header of the list is extracted and bound to the variable h, while the rest (the tail) is bound to t; in this case, nothing is done with h. (in fact, it is better to indicate that the header will never be used by using a wildcard _ instead of h, which indicates that it is a placeholder for variables that will never be used). But t is passed recursively to count, as in the previous example. Also note that each expression in Scala will implicitly return a value; in this case, the result of the pattern matching expression is a recursive call to count + 1, and when the end of the list is reached, the result is 0.
Given the same amount of code, what is the value of using pattern matching? In fact, for simpler code, the value of pattern matching is not obvious. But for slightly more complex code, such as extending the example to match a specific value, pattern matching is very helpful.
Listing 12. Pattern matching
@ Test def recurseWithPMAndSayHi = {val myVIPList = "Ted":: "Amanda":: "Luke":: "Don":: "Martin":: Nil var foundAmanda = false def count (VIPs: List [String]): Int = {VIPs match {case "Amanda":: t = > System.out.println ("Hey, Amanda!"); foundAmanda = true Count (t) + 1 case h:: t = > count (t) + 1 case Nil = > 0}} assertEquals (count (myVIPList), myVIPList.length) assertTrue (foundAmanda)}
Examples quickly become very complex, especially regular expressions or XML nodes, and begin to use pattern matching methods heavily. The use of pattern matching is also not limited to lists; there is no reason why we should not extend it to the previous array example. In fact, the following is an array example of the previous recurseWithPMAndSayHi test:
Listing 13. Extend pattern matching to an array
Test def recurseWithPMAndSayHi = {val myVIPList = Array ("Ted", "Amanda", "Luke", "Don", "Martin") var foundAmanda = false myVIPList.foreach ((s) = > s match {case "Amanda" = > System.out.println ("Hey, Amanda!") FoundAmanda = true case _ = >; / / Do nothing}) assertTrue (foundAmanda)}
If you want to practice, try to build a recursive version of listing 13, but there is no need to declare a modifiable var within the scope of recurseWithPMAndSayHi. Tip: multiple pattern matching code blocks are required
Thank you for reading this article carefully. I hope the article "how to use tuples, arrays and lists from Java to Scala" shared by the editor will be helpful to you. At the same time, I also hope you will support us and pay attention to the industry information channel. More related knowledge is waiting for you to learn!
Welcome to subscribe "Shulou Technology Information " to get latest news, interesting things and hot topics in the IT industry, and controls the hottest and latest Internet news, technology news and IT industry trends.
Views: 266
*The comments in the above article only represent the author's personal views and do not represent the views and positions of this website. If you have more insights, please feel free to contribute and share.
Continue with the installation of the previous hadoop.First, install zookooper1. Decompress zookoope
"Every 5-10 years, there's a rare product, a really special, very unusual product that's the most un
© 2024 shulou.com SLNews company. All rights reserved.