Many in the Java development community are hoping to glean clues about Oracle's vision of the future of Java (assuming successful acquisition of Sun by Oracle) at next week's Oracle OpenWorld (11-15 October 2009 at Moscone Center in San Francisco). In this blog post, I briefly look at some Java-related information we might expect to come out of OpenWorld.
Both Oracle and Sun Microsystems are emphasizing each other's partnerships with one another in advance of this event. Sun has a web page called Java at Oracle OpenWorld that includes a listing of "Oracle OpenWorld Java Sessions", "Oracle Develop Java Sessions", and mention of James Gosling's Oracle Develop keynote presentation Top Ten Things You May Not Know about Sun Software. Sun also has a Feature Story that includes celebration of their "quarter century partnership with Oracle". According to this page, Sun employees will lead thirty general sessions and ten developer sessions. This page also references the Larry Ellison/Scott McNealy keynote on Sunday (tomorrow).
Oracle has been an user and supporter of Java for some time and has its own page on its partnership with Sun. Oracle also features a site on Sun-sponsored Oracle Develop.
There are many resources for additional information regarding Oracle OpenWorld. These include The OTN Guide to Oracle OpenWorld 2009, which features a section of "community streams" that I think may have the most potential interest to me during the week. These "community streams" include Oracle OpenWorld Live (also covered in this blog post) and Blogs about Oracle OracleWorld 2009 (see also Oracle blogs on OpenWorld).
Third-party coverage of Oracle and Sun at Oracle OpenWorld includes The Register's Sun and Oracle to Pimp Synergies at OpenWorld, Oracle Takeover of Sun to be Center Stage at OpenWorld, and OpenWorld to Shed Light on Oracle's Java Plans.
I look forward to the blogs and other accounts that come out of OpenWorld 2009 this coming week. At the very least, there should be plenty of fodder for continued theorizing and controversy about the future of Java. Some believe that Oracle's purchase of Sun is good for Java while others are not so sure. I don't expect many definitive statements regarding Java beyond what was stated by Oracle representatives at 2009 JavaOne, but I do expect there to be interesting observations and read-between-the-lines conclusions made perhaps even when not warranted.
Thứ Bảy, 10 tháng 10, 2009
Lists of Popular Software Development Blogs
There seem to be all kinds of lists of top software development and technical blogs. On the one hand, this does not matter that much to me because of the existence of powerful search engines such as Google and powerful development-specific aggregation sites such DZone. Search engines allow me to find an answer to a particular problem I am facing and don't limit me to blogs. If I do want to focus on blogs, blog-specific search engines such as Google Blog Search are useful and allow the query to be limited to specified recent timeframes (such as blogs posted in the past week). When I am looking for exposure to new things that I don't even know enough about to generate a useful search query, a site like DZone fills that need nicely.
Because search engines provide answers to current problems and technology-focused social aggregation sites expose me to new ideas and concepts, I often don't find the need to limit myself to reading a particular blog regularly. That being said, there are cases where a single blog ends up helping me enough times via search or via aggregation site that I realize it's worth reading proactively. I usually determine these blogs from my own experience, but it is still worth seeing which blogs others think are among the best in software development. In the remainder of this blog post, I reference some of these collected lists of "best," "top," or "most popular" software development blogs. I also make excuses for why my blog did not make any of these lists. :)
NOOP.NL: Top 200 Blogs for Developers
Jurgen Appelo's Top 200 Blogs for Developers is perhaps the most comprehensive (200 blogs!), most frequently updated (quarterly), and most systematic of the lists of software development blogs. This list is based on Google Page Rank, Google links, and several other ranking sources. Greater detail on how this list was created is available in How to Make a Top Blog List. Jurgen says that he does not include blogs in this list that are narrowly focused on a single language, but I like to think that the reason my blog did not make the list is that he is not aware of it to even consider it for the Top 200.
64 High-Ranked Blogs for Developers
The blogs cited on 64 High-Ranked Blogs for Developers seem to be those with highest Page Rank (each has a Page Rank of six or higher, which is impressive for a development-focused blog). I like the appearance of this list with screen snapshots, the page rank, and a link to the blog's main page. It is a simple and elegant web page design. I am fairly certain that my blog's Page Rank (5) is the reason for exclusion from this list. At least that's what I tell myself because I don't like the idea that my blog did not make the list due to its lack of impressive design.
SD Times Best Blogs of 2007
SD Times on the Web features an article Best Blogs of 2007 includes "most interesting technology blogs" that range from "the authoritative to the wacky." I like to think that my blog did not make this list because I did not start writing in until late 2007 (October).
Several Tech Blogs Worth Exploring. Oh Yeah, All by Women.
This recent (October 2009) blog post looks at a wide spectrum of technical blogs written by women. I like to think my blog did not make this list because of my gender.
Top 10 Recent Blogs
Not so recent anymore (December 2005), many of the blogs listed at MEME: Top 10 Recent Blogs are still popular nearly four years later. When this list came out, my first blog entry would not be written for nearly another two years.
Five Great Software Development Blogs
The March 2007 post 5 Great Software Development Blogs provides a paragraph explanation of five preferred software development blogs and lists two more without explanation as blogs worth a time investment. Again, I am able to rationalize to myself that my blog is not on this list because it wasn't even around at that time.
My Personal Favorite Software Development Blogs
If I cared more about having my blog make a list of "top software development blogs," I would make up my own list and ignore any idea of objectivity and put my own blog on the list (probably as #1). However, the truth is that I really don't have a list of favorite blogs. Rather, I do recognize some blogs that consistently provide the answers I seek via search engine or learn about a new post via a social aggregation site. Instead of listing particular blogs here, what I will state is the types of software development blogs that I prefer. In general, I have found that I prefer blog posts that meet one or more of the following criteria (in some cases, these are conflicting criteria and it is nearly impossible to satisfy both):
1. Very Specific and Detailed - These tend to be preferred when I seek an answer to a specific and often somewhat tricky question or problem. An example of this was was Mike Morearty's Common E4X Pitfalls post that specifically addressed problems I ran into when first using E4X with Flex.
2. Experienced-based - I appreciate blogs written with the voice of experience. I often don't need a post repeating what all the books and articles say; instead I need to know the intricacies and nuances of a particular approach, language, framework, methodology, or other software development concept.
3. Lessons Learned from Others' Mistakes - I make enough of my own mistakes that I appreciate when others make potential mistakes first and then warn me and the rest of us about these. These refreshingly honest blog posts can be difficult to write, but can be of significant value to the rest of us.
4. Contrarian - It is easy to be a lemming in the software development. I appreciate blogs that challenge this mentality and challenge the direction of the software development herd. I don't always agree with the contrarians (the herd is correct sometimes), but I think the consideration of multiple viewpoints is extremely valuable. Note that I don't want more simple-minded posts that say, "Such-and-such sucks," but rather want more contrarian posts that actually back up their contrarian opinion. Examples of blogs that often have these types of articles include Software Reality and The Programmer Has No Clothes.
5. Fresh Perspective - One of the reasons I prefer to choose the blog posts I read via search engine and via browsing of social aggregation sites is that these approaches work best for discovering fresh new perspectives. The best of the blogs contained in the lists described in this post are amazing in the sense that they almost all are long-running blogs (a requirement for being popular) that are consistently useful (another requirement for being popular). However, some of the freshest perspectives can sometimes come from those newest to software development and/or newest to blogging.
6. Link and Reference Heavy - My favorite blog posts are typically link-heavy and/or provide many references. If I really like the subject of the blog post, chances are I'm going to want to read similar material. It is also likely I'd like to see other posts that inspired the post I am enjoying. Furthermore, I sometimes need further explanation of more complex terms covered in a great post and can find that more easily if it is linked to. It is my opinion that one of the best features of the software development corner of the blogosphere is the community nature of it. The more interconnected the blogs are, the more we can gain these advantages. It seems that I have found "just the right blog post" a countless number of times not directly from my favorite search engine or from my favorite social aggregation site, but have instead found it via a link from the page found from the search engine or aggregation site.
Conclusion
There are many excellent blogs related to software development out there. With no hope of ever reading them all, the lists outlined above can be useful in determining which to focus on if one wants to read a particular blog regularly. In many respects, the plethora of great software development blogs convinces me more than ever of the value of effective use of a good search engine and of a good social aggregation site to allow me to see either the most applicable blogs to a particular problem or to see the blog posts that are generally deemed by the community to be the most significant.
Because search engines provide answers to current problems and technology-focused social aggregation sites expose me to new ideas and concepts, I often don't find the need to limit myself to reading a particular blog regularly. That being said, there are cases where a single blog ends up helping me enough times via search or via aggregation site that I realize it's worth reading proactively. I usually determine these blogs from my own experience, but it is still worth seeing which blogs others think are among the best in software development. In the remainder of this blog post, I reference some of these collected lists of "best," "top," or "most popular" software development blogs. I also make excuses for why my blog did not make any of these lists. :)
NOOP.NL: Top 200 Blogs for Developers
Jurgen Appelo's Top 200 Blogs for Developers is perhaps the most comprehensive (200 blogs!), most frequently updated (quarterly), and most systematic of the lists of software development blogs. This list is based on Google Page Rank, Google links, and several other ranking sources. Greater detail on how this list was created is available in How to Make a Top Blog List. Jurgen says that he does not include blogs in this list that are narrowly focused on a single language, but I like to think that the reason my blog did not make the list is that he is not aware of it to even consider it for the Top 200.
64 High-Ranked Blogs for Developers
The blogs cited on 64 High-Ranked Blogs for Developers seem to be those with highest Page Rank (each has a Page Rank of six or higher, which is impressive for a development-focused blog). I like the appearance of this list with screen snapshots, the page rank, and a link to the blog's main page. It is a simple and elegant web page design. I am fairly certain that my blog's Page Rank (5) is the reason for exclusion from this list. At least that's what I tell myself because I don't like the idea that my blog did not make the list due to its lack of impressive design.
SD Times Best Blogs of 2007
SD Times on the Web features an article Best Blogs of 2007 includes "most interesting technology blogs" that range from "the authoritative to the wacky." I like to think that my blog did not make this list because I did not start writing in until late 2007 (October).
Several Tech Blogs Worth Exploring. Oh Yeah, All by Women.
This recent (October 2009) blog post looks at a wide spectrum of technical blogs written by women. I like to think my blog did not make this list because of my gender.
Top 10 Recent Blogs
Not so recent anymore (December 2005), many of the blogs listed at MEME: Top 10 Recent Blogs are still popular nearly four years later. When this list came out, my first blog entry would not be written for nearly another two years.
Five Great Software Development Blogs
The March 2007 post 5 Great Software Development Blogs provides a paragraph explanation of five preferred software development blogs and lists two more without explanation as blogs worth a time investment. Again, I am able to rationalize to myself that my blog is not on this list because it wasn't even around at that time.
My Personal Favorite Software Development Blogs
If I cared more about having my blog make a list of "top software development blogs," I would make up my own list and ignore any idea of objectivity and put my own blog on the list (probably as #1). However, the truth is that I really don't have a list of favorite blogs. Rather, I do recognize some blogs that consistently provide the answers I seek via search engine or learn about a new post via a social aggregation site. Instead of listing particular blogs here, what I will state is the types of software development blogs that I prefer. In general, I have found that I prefer blog posts that meet one or more of the following criteria (in some cases, these are conflicting criteria and it is nearly impossible to satisfy both):
1. Very Specific and Detailed - These tend to be preferred when I seek an answer to a specific and often somewhat tricky question or problem. An example of this was was Mike Morearty's Common E4X Pitfalls post that specifically addressed problems I ran into when first using E4X with Flex.
2. Experienced-based - I appreciate blogs written with the voice of experience. I often don't need a post repeating what all the books and articles say; instead I need to know the intricacies and nuances of a particular approach, language, framework, methodology, or other software development concept.
3. Lessons Learned from Others' Mistakes - I make enough of my own mistakes that I appreciate when others make potential mistakes first and then warn me and the rest of us about these. These refreshingly honest blog posts can be difficult to write, but can be of significant value to the rest of us.
4. Contrarian - It is easy to be a lemming in the software development. I appreciate blogs that challenge this mentality and challenge the direction of the software development herd. I don't always agree with the contrarians (the herd is correct sometimes), but I think the consideration of multiple viewpoints is extremely valuable. Note that I don't want more simple-minded posts that say, "Such-and-such sucks," but rather want more contrarian posts that actually back up their contrarian opinion. Examples of blogs that often have these types of articles include Software Reality and The Programmer Has No Clothes.
5. Fresh Perspective - One of the reasons I prefer to choose the blog posts I read via search engine and via browsing of social aggregation sites is that these approaches work best for discovering fresh new perspectives. The best of the blogs contained in the lists described in this post are amazing in the sense that they almost all are long-running blogs (a requirement for being popular) that are consistently useful (another requirement for being popular). However, some of the freshest perspectives can sometimes come from those newest to software development and/or newest to blogging.
6. Link and Reference Heavy - My favorite blog posts are typically link-heavy and/or provide many references. If I really like the subject of the blog post, chances are I'm going to want to read similar material. It is also likely I'd like to see other posts that inspired the post I am enjoying. Furthermore, I sometimes need further explanation of more complex terms covered in a great post and can find that more easily if it is linked to. It is my opinion that one of the best features of the software development corner of the blogosphere is the community nature of it. The more interconnected the blogs are, the more we can gain these advantages. It seems that I have found "just the right blog post" a countless number of times not directly from my favorite search engine or from my favorite social aggregation site, but have instead found it via a link from the page found from the search engine or aggregation site.
Conclusion
There are many excellent blogs related to software development out there. With no hope of ever reading them all, the lists outlined above can be useful in determining which to focus on if one wants to read a particular blog regularly. In many respects, the plethora of great software development blogs convinces me more than ever of the value of effective use of a good search engine and of a good social aggregation site to allow me to see either the most applicable blogs to a particular problem or to see the blog posts that are generally deemed by the community to be the most significant.
Firsthand Frustration with Interface Inaccessiblity
Most of us in the software development business are probably at least aware of accessibility issues associated with software development (particularly user interface development). However, I find that I usually understand the need for something better when I experience the need myself. Although I have learned some lessons about the importance of accessibility from those around me with accessibility issues, I recently encountered a personal experience with an interface that was rendered largely inaccessible for me. It was a frustrating experience, but has provided me with new understanding and empathy for those who are forced to use interfaces that lack sufficiently accessible design. In this post, I look at the personal frustration I felt firsthand during this experience and review what I've learned from it.
Those who know me or have attended one of my technical presentations would probably agree with my statement that I have relatively deep voice. One of the disadvantages of having a relatively deeper voice than "the typical range" of voices is that careful enunciation is more important to convey what I'm trying to say. Years ago when my wife and I went to Disney World, I was impressed at the advancements in speech recognition demonstrated at the Epcot Center. Although these voice recognition systems worked well for everyone in our party, they did not even acknowledge that I was speaking. Since then, I've noticed that most voice recognition software has trouble handling my voice.
In this recent customer service fiasco, I needed to change some information on one of my accounts. The automated telephone system gave me the option of using telephone keys or voice recognition. Because I am all too familiar with the limitations in speech/voice recognition related to my deep voice, I chose the option of using the telephone keys. For most of the options, this worked well. Unfortunately, there were a couple of prompts during the process that required me to speak the selection. My guess is that the system was built this way because of the difficultly of differentiating between numerals and letters based on telephone keys pressed. Whatever the reason for this design and as no surprise to me, the voice recognition did not work well with my voice.
The voice recognition service kept misinterpreting at least one of the letters that I spoke. When I tried to enunciate them more clearly, any late emphasis in speaking a particular letter was interpreted as a second letter. It was bad enough that I had to keep repeating the same string of letters and numerals, but it was even more frustrating when the system would report automatic transfer to a customer service agent after three failed attempts. This would not have been so bad except for the fact that the "transfer" ended up in the call hanging up after about 15 seconds of various noises. After experiencing this twice, I really wished that I could continue trying to voice the letters in a way the system could understand rather than being "transferred" again.
In this case, the company I was working with has a virtual monopoly on the service that I purchase from them. This may be one reason that they get away with a system that "transfers" a customer by hanging up on that customer. It also made me realize that their telephone system was basically inaccessible to me and, if I had any alternatives or substitutions for their service, would drive me to that competitor. I asked myself why they didn't have an online presence where I could enter letters and numerals from my computer keyboard in such a way that they could easily differentiate between the two and I would not need to worry about inaccessibility due to the deepness of my voice.
From all this, I now appreciate more than ever the importance of building accessible software systems. Several years ago, I learned the importance of dealing with colors when one of the highest ranking officials representing my client had severe color blindness. I had built a Flex-based demonstration for this client that relied heavily on colors and contrasts for visual effect. This client representative could barely make out some of the features after significant effort. Although my color scheme enhanced the conveyance of information for the "typical" viewer, it made it worse for him. I experienced the same frustration with the telephone system: it probably works well for the "typical" user but was extremely frustrating and essentially inaccessible for me.
The Electronic and Information Technology Accessibility Standards (Section 508) states its purpose as follows:
This requirement for federal systems (United States) to be accessible to public users is particularly important because there is usually no competition for these services. In other words, the users are captive customers and need to be able to access their services. In the competitive marketplace, it makes sense to provide accessible services so that potential customers will not move to the competition.
It is important to develop our services in an accessible way so that potential customers do not give up on us and leave in frustration. Popular programming languages, frameworks, and platforms often provide assistance in creating more accessible software. Examples of this include Java SE Desktop Availability (including the Java Accessibility API and the Java Accessibility Utilities), Flex Accessibility (including accessible components, tutorials, and best practices), and .NET accessibility features (such as the AccessibleObject class).
Accessibility Rule of Thumb
As a rule of thumb, it seems that an interface should always have at least two ways to convey and accept information. If the telephone system uses voice recognition, it should probably also be built for 100% support for pressed keys for those of us with "voice challenges." Similarly, the voice recognition is likely a nice alternative to pressed keys for those who have poor eyesight or otherwise have difficulty pressing the correct telephone keys. Our interfaces are more likely to be generally usable if they provide more than one way to accomplish each task. Some people hear better than they see and some people see better than they hear.
Conclusion
It can be an extremely frustrating experience to deal with an interface that likely works for "most people," but does not work for me because of assumptions made when designing the interface.
Additional Interface Usability/Accessibility References
⇒ Electronic and Information Technology Accessibility Standards (Section 508)
⇒ Usability Approach to Accessibility (focus on tip #17)
⇒ Understanding Web Accessibility
⇒ The Resolution Race: Perpetuating Inaccessible Computing
⇒ Clinton Pledges Funds for Net Accessibility Research
Those who know me or have attended one of my technical presentations would probably agree with my statement that I have relatively deep voice. One of the disadvantages of having a relatively deeper voice than "the typical range" of voices is that careful enunciation is more important to convey what I'm trying to say. Years ago when my wife and I went to Disney World, I was impressed at the advancements in speech recognition demonstrated at the Epcot Center. Although these voice recognition systems worked well for everyone in our party, they did not even acknowledge that I was speaking. Since then, I've noticed that most voice recognition software has trouble handling my voice.
In this recent customer service fiasco, I needed to change some information on one of my accounts. The automated telephone system gave me the option of using telephone keys or voice recognition. Because I am all too familiar with the limitations in speech/voice recognition related to my deep voice, I chose the option of using the telephone keys. For most of the options, this worked well. Unfortunately, there were a couple of prompts during the process that required me to speak the selection. My guess is that the system was built this way because of the difficultly of differentiating between numerals and letters based on telephone keys pressed. Whatever the reason for this design and as no surprise to me, the voice recognition did not work well with my voice.
The voice recognition service kept misinterpreting at least one of the letters that I spoke. When I tried to enunciate them more clearly, any late emphasis in speaking a particular letter was interpreted as a second letter. It was bad enough that I had to keep repeating the same string of letters and numerals, but it was even more frustrating when the system would report automatic transfer to a customer service agent after three failed attempts. This would not have been so bad except for the fact that the "transfer" ended up in the call hanging up after about 15 seconds of various noises. After experiencing this twice, I really wished that I could continue trying to voice the letters in a way the system could understand rather than being "transferred" again.
In this case, the company I was working with has a virtual monopoly on the service that I purchase from them. This may be one reason that they get away with a system that "transfers" a customer by hanging up on that customer. It also made me realize that their telephone system was basically inaccessible to me and, if I had any alternatives or substitutions for their service, would drive me to that competitor. I asked myself why they didn't have an online presence where I could enter letters and numerals from my computer keyboard in such a way that they could easily differentiate between the two and I would not need to worry about inaccessibility due to the deepness of my voice.
From all this, I now appreciate more than ever the importance of building accessible software systems. Several years ago, I learned the importance of dealing with colors when one of the highest ranking officials representing my client had severe color blindness. I had built a Flex-based demonstration for this client that relied heavily on colors and contrasts for visual effect. This client representative could barely make out some of the features after significant effort. Although my color scheme enhanced the conveyance of information for the "typical" viewer, it made it worse for him. I experienced the same frustration with the telephone system: it probably works well for the "typical" user but was extremely frustrating and essentially inaccessible for me.
The Electronic and Information Technology Accessibility Standards (Section 508) states its purpose as follows:
The purpose of this part is to implement section 508 of the Rehabilitation Act of 1973, as amended (29 U.S.C. 794d). Section 508 requires that when Federal agencies develop, procure, maintain, or use electronic and information technology, Federal employees with disabilities have access to and use of information and data that is comparable to the access and use by Federal employees who are not individuals with disabilities, unless an undue burden would be imposed on the agency. Section 508 also requires that individuals with disabilities, who are members of the public seeking information or services from a Federal agency, have access to and use of information and data that is comparable to that provided to the public who are not individuals with disabilities, unless an undue burden would be imposed on the agency.
This requirement for federal systems (United States) to be accessible to public users is particularly important because there is usually no competition for these services. In other words, the users are captive customers and need to be able to access their services. In the competitive marketplace, it makes sense to provide accessible services so that potential customers will not move to the competition.
It is important to develop our services in an accessible way so that potential customers do not give up on us and leave in frustration. Popular programming languages, frameworks, and platforms often provide assistance in creating more accessible software. Examples of this include Java SE Desktop Availability (including the Java Accessibility API and the Java Accessibility Utilities), Flex Accessibility (including accessible components, tutorials, and best practices), and .NET accessibility features (such as the AccessibleObject class).
Accessibility Rule of Thumb
As a rule of thumb, it seems that an interface should always have at least two ways to convey and accept information. If the telephone system uses voice recognition, it should probably also be built for 100% support for pressed keys for those of us with "voice challenges." Similarly, the voice recognition is likely a nice alternative to pressed keys for those who have poor eyesight or otherwise have difficulty pressing the correct telephone keys. Our interfaces are more likely to be generally usable if they provide more than one way to accomplish each task. Some people hear better than they see and some people see better than they hear.
Conclusion
It can be an extremely frustrating experience to deal with an interface that likely works for "most people," but does not work for me because of assumptions made when designing the interface.
Additional Interface Usability/Accessibility References
⇒ Electronic and Information Technology Accessibility Standards (Section 508)
⇒ Usability Approach to Accessibility (focus on tip #17)
⇒ Understanding Web Accessibility
⇒ The Resolution Race: Perpetuating Inaccessible Computing
⇒ Clinton Pledges Funds for Net Accessibility Research
Thứ Năm, 8 tháng 10, 2009
More on the Future of JavaOne
Twice previously (April 2009 and June 2009), I publicly pondered the future of JavaOne given Oracle's announced acquiring of Sun Microsystems. Toward the end of the article "Sun management stumbled on EU Oracle probe", The Register now claims that "there will be no more JavaOne conferences under the new Oracle owner."
Until/unless Oracle officially announces the end of JavaOne, we still do not know for certain the future of JavaOne. However, for reasons that I outlined previously, it will not be all that surprising if Oracle does merge JavaOne with its Oracle OpenWorld conference.
In the DZone article JavaOne: Is the Party Over?, Mitch Pronschinske quotes several people in the industry regarding their opinions on the rumor that Oracle will drop JavaOne. There are also comments from other readers of the article. I have previously blogged on the observations about the future of JavaOne made by people attending 2009 JavaOne.
None of this confirms with certainty the future of JavaOne. It is doubtful that we'll know anything certain until after the current transaction between Oracle and Sun is completed. However, my feeling is that even if JavaOne continues on, it will be quite different in the future.
Until/unless Oracle officially announces the end of JavaOne, we still do not know for certain the future of JavaOne. However, for reasons that I outlined previously, it will not be all that surprising if Oracle does merge JavaOne with its Oracle OpenWorld conference.
In the DZone article JavaOne: Is the Party Over?, Mitch Pronschinske quotes several people in the industry regarding their opinions on the rumor that Oracle will drop JavaOne. There are also comments from other readers of the article. I have previously blogged on the observations about the future of JavaOne made by people attending 2009 JavaOne.
None of this confirms with certainty the future of JavaOne. It is doubtful that we'll know anything certain until after the current transaction between Oracle and Sun is completed. However, my feeling is that even if JavaOne continues on, it will be quite different in the future.
Thứ Hai, 5 tháng 10, 2009
RMOUG: Beware Triggers and DBA Code of Ethics
The Rocky Mountain Oracle Users Group (RMOUG) is well-known in the Oracle database administrator community. This is one of the most successful models I have seen of an effective user group and its annual Training Days conference is particularly well regarded. Although I am not a database administrator (DBA), I still found three DBA-centric articles in the current edition of the quarterly RMOUG newsletter (RMOUG SQL>UPDATE_RMOUG) to be worth the read and worth mentioning here.
The three articles in the Fall 2009 edition of SQL>UPDATE_RMOUG are "Beware..." (Another Look at Triggers), "Database Administrator's Code of Ethics", and "Using the PL/SQL Profiler." In this blog posting, I'll look briefly at the first two of these three articles.
Beware ... Triggers
Tom Kyte is one of the best-known experts in the Oracle community. He authors the askTom site and is a Senior Technical Architect at Oracle. His Blogger profile has been viewed approximately 87 thousand times. When I give a presentation during the same conference slot he is presenting in at a database-oriented conference, I can expect a very small audience at my presentation.
In his article "Beware...", Kyte writes, "At first, I thought triggers were the coolest thing ever ... something that I as a developer could use to perform 'magic.'" Kyte goes on to explain that the "forgotten trigger has bitten me many times in the past." Kyte also states, "If I could remove a few features from the database -- it would be triggers and when others then null."
After providing many examples of trigger abuse, Kyte concludes, "When used correctly and sparingly, triggers can be a positive thing. It is when they are used for every and anything that they become a really bad idea. ... Triggers should be used when there is no other way to achieve your goal. They should be the last resort."
I am not aware of this article being available online, but you can reference Kyte's The Trouble with Triggers for more information from Kyte on triggers.
DBA Code of Ethics
In the article Database Administrator's Code of Ethics, OracleGiants editor Brian Carr states that the purpose of this article is "to analyze the social and ethical responsibility of Database Administrators (DBAs)." In this article, Carr defines a DBA as "the person in charge of managing the relational database and its access rights" and references the Wikipedia article on database administration.
In explaining why DBAs should have a code of ethics, Carr points out that DBAs, like their systems administration cousins, "generally have high levels of access" in various powerful organizations with highly sensitive data. To support this position, Carr references the InfoSec News story The Data Security Weak Link.
Carr points out that physicians and certain types of engineers have their respective codes of ethics. He suggests that DBAs should "also be required to take an oath, or swear to practice by a strict Code of Ethics" because "people and organizations do trust extremely confidential and sometimes very personal information to a Database Administrator."
In this article, Carr first references Stephen Wynkoop's proposed SSWUG DBA Code of Ethics before outlining his (Carr's) own proposed code of ethics that adds fiduciary responsibility, limitation of data access to only that required to do the job, and "a more professional tone" to the SSWUG DBA Code of Ethics. In this article, Carr briefly describes six principles (prudence, justice, temperance, courage, responsibility, and trustworthiness) behind the proposed code of ethics.
As I read this article, I definitely saw some things that I liked, but I also wondered how realistically it would be followed. It would be interesting to know if there is any proven correlation between existing professions with codes of ethics and better behavior because of the existence of a code of ethics. I believe that a code of ethics could be a great educational tool to help younger people in a profession learn what is considered ethical and what is considered bad form. However, it is likely that a code of ethics provides very little deterrent to a person lacking concern for rules, laws, or ethical behavior.
Carr concludes his article with a realistic assessment of the potential advantages of a DBA code of ethics. He states, "The Code of Ethics would likely never be enforced, other than what is considered to be unlawful, however, the code is about striving to be a more cohesive profession when it comes to what we do and how we do it."
Personally, as a customer or patient whose records are at the mercy of DBAs out there, I would like to see some guidance related to what is considered ethical behavior. As a software developer, I cannot help ask myself questions like "Would a code of ethics benefit software developers?" and "Would software developers care about a code of ethics?" In other words, would having a code of ethics for software developers change anything?
This article "Database Administrator's Code of Ethics" is hosted online and this online version includes references at the end of the article. The print version of the article in SQL>UPDATE states that this article is a "collaboration between Burleson Consulting and Brian Carr." I bring this up because Burleson Consulting hosts a brief article called Ethics for the Oracle Professional.
Conclusion
Although I am not a DBA, I found these articles to be thought-provoking. Many of the reasons Kyte outlines for not using triggers can apply to similar "magic" and trickery we might employ in software development. I feel about aspect-oriented programming (and some other software development concepts) similarly to how Kyte feels about triggers: they can be very helpful when most appropriate, but can be a maintenance nightmare when used indiscriminately. Too much "magic" can be too difficult to read and maintain.
Like DBAs, software developers (especially those that maintain production software) have access to sensitive data. In addition, developers are in a position to introduce vulnerabilities in software's security (such as the back door popularized in War Games). There is no question we need software developers to rely ethically, but the question is whether a code of ethics would have any influence on that.
The three articles in the Fall 2009 edition of SQL>UPDATE_RMOUG are "Beware..." (Another Look at Triggers), "Database Administrator's Code of Ethics", and "Using the PL/SQL Profiler." In this blog posting, I'll look briefly at the first two of these three articles.
Beware ... Triggers
Tom Kyte is one of the best-known experts in the Oracle community. He authors the askTom site and is a Senior Technical Architect at Oracle. His Blogger profile has been viewed approximately 87 thousand times. When I give a presentation during the same conference slot he is presenting in at a database-oriented conference, I can expect a very small audience at my presentation.
In his article "Beware...", Kyte writes, "At first, I thought triggers were the coolest thing ever ... something that I as a developer could use to perform 'magic.'" Kyte goes on to explain that the "forgotten trigger has bitten me many times in the past." Kyte also states, "If I could remove a few features from the database -- it would be triggers and when others then null."
After providing many examples of trigger abuse, Kyte concludes, "When used correctly and sparingly, triggers can be a positive thing. It is when they are used for every and anything that they become a really bad idea. ... Triggers should be used when there is no other way to achieve your goal. They should be the last resort."
I am not aware of this article being available online, but you can reference Kyte's The Trouble with Triggers for more information from Kyte on triggers.
DBA Code of Ethics
In the article Database Administrator's Code of Ethics, OracleGiants editor Brian Carr states that the purpose of this article is "to analyze the social and ethical responsibility of Database Administrators (DBAs)." In this article, Carr defines a DBA as "the person in charge of managing the relational database and its access rights" and references the Wikipedia article on database administration.
In explaining why DBAs should have a code of ethics, Carr points out that DBAs, like their systems administration cousins, "generally have high levels of access" in various powerful organizations with highly sensitive data. To support this position, Carr references the InfoSec News story The Data Security Weak Link.
Carr points out that physicians and certain types of engineers have their respective codes of ethics. He suggests that DBAs should "also be required to take an oath, or swear to practice by a strict Code of Ethics" because "people and organizations do trust extremely confidential and sometimes very personal information to a Database Administrator."
In this article, Carr first references Stephen Wynkoop's proposed SSWUG DBA Code of Ethics before outlining his (Carr's) own proposed code of ethics that adds fiduciary responsibility, limitation of data access to only that required to do the job, and "a more professional tone" to the SSWUG DBA Code of Ethics. In this article, Carr briefly describes six principles (prudence, justice, temperance, courage, responsibility, and trustworthiness) behind the proposed code of ethics.
As I read this article, I definitely saw some things that I liked, but I also wondered how realistically it would be followed. It would be interesting to know if there is any proven correlation between existing professions with codes of ethics and better behavior because of the existence of a code of ethics. I believe that a code of ethics could be a great educational tool to help younger people in a profession learn what is considered ethical and what is considered bad form. However, it is likely that a code of ethics provides very little deterrent to a person lacking concern for rules, laws, or ethical behavior.
Carr concludes his article with a realistic assessment of the potential advantages of a DBA code of ethics. He states, "The Code of Ethics would likely never be enforced, other than what is considered to be unlawful, however, the code is about striving to be a more cohesive profession when it comes to what we do and how we do it."
Personally, as a customer or patient whose records are at the mercy of DBAs out there, I would like to see some guidance related to what is considered ethical behavior. As a software developer, I cannot help ask myself questions like "Would a code of ethics benefit software developers?" and "Would software developers care about a code of ethics?" In other words, would having a code of ethics for software developers change anything?
This article "Database Administrator's Code of Ethics" is hosted online and this online version includes references at the end of the article. The print version of the article in SQL>UPDATE states that this article is a "collaboration between Burleson Consulting and Brian Carr." I bring this up because Burleson Consulting hosts a brief article called Ethics for the Oracle Professional.
Conclusion
Although I am not a DBA, I found these articles to be thought-provoking. Many of the reasons Kyte outlines for not using triggers can apply to similar "magic" and trickery we might employ in software development. I feel about aspect-oriented programming (and some other software development concepts) similarly to how Kyte feels about triggers: they can be very helpful when most appropriate, but can be a maintenance nightmare when used indiscriminately. Too much "magic" can be too difficult to read and maintain.
Like DBAs, software developers (especially those that maintain production software) have access to sensitive data. In addition, developers are in a position to introduce vulnerabilities in software's security (such as the back door popularized in War Games). There is no question we need software developers to rely ethically, but the question is whether a code of ethics would have any influence on that.
Groovy JDK (GDK): Object[] and T[]
The Groovy JDK (GDK) provides many convenience methods that can be invoked on arrays. The GDK includes specific support for many array types such as Byte[], byte[], boolean[], double[], float[], int[], and long[]. The GDK also supports String[], T[], and Object[]. I'll focus on the last two (
In this post, I'll have the some of the Groovy code reference a Java class called
Person.java
In Java, there isn't much one can do directly with an array of the above objects. The next code sample demonstrates some of the limited functionality available with direct use of an array:
JavaArrays.java
When the above code is executed, the output looks like that shown in the next screen snapshot:

The output of a
In this first snippet from my Groovy script
method is demonstrated. This method allows an array of Objects to be treated as a Set of Objects or a List of Objects. The version that provides a SortedSet is commented out because the objects in the collection need to be Comparable for a
groovyObjectArray.groovy (part 1)
The output for these first few lines of Groovy code is shown next.

groovyObjectArray.groovy (part 2)
The output from the above snippet of the script is shown next.

As the above code listing and its corresponding output indicate, the Object[].toString() and Object[].toArrayString() methods provide nice String representations of the array contents. The Object[].size() method is a method-based approach to get the size or length of the array. The Object[].join(String) method joins the String representations of the elements of the array to each other with the provided String-based separator joining them. The Object[].count(Object) method has only been available since Groovy 1.6.4 and provides the number of instances of the provided Object within that array.
The third and final part of the
groovyObjectArray.groovy (part 3)
The output from the above is shown in the next screen snapshot.

This posting has demonstrated the useful convenience methods provided for array access and manipulation in Groovy GDK with Object[] and T[].
Object[] and T[]) in this blog posting.In this post, I'll have the some of the Groovy code reference a Java class called
Person.java and the code listing for that class is shown next.Person.java
package dustin.examples;
/**
* Simple class to be used in Groovy Object[] examples.
*/
public class Person
{
private final String lastName;
private final String firstName;
public Person(final String newLastName, final String newFirstName)
{
this.lastName = newLastName;
this.firstName = newFirstName;
}
@Override
public boolean equals(Object obj)
{
if (obj == null)
{
return false;
}
if (getClass() != obj.getClass())
{
return false;
}
final Person other = (Person) obj;
if (this == null ? other != null : !this.lastName.equals(other.lastName))
{
return false;
}
if (this == null ? other != null : !this.firstName.equals(other.firstName))
{
return false;
}
return true;
}
@Override
public int hashCode()
{
int hash = 3;
hash = 97 * hash + (this.lastName != null ? this.lastName.hashCode() : 0);
hash = 97 * hash + (this.firstName != null ? this.firstName.hashCode() : 0);
return hash;
}
@Override
public String toString()
{
return this.firstName + " " + this.lastName;
}
}
In Java, there isn't much one can do directly with an array of the above objects. The next code sample demonstrates some of the limited functionality available with direct use of an array:
JavaArrays.java
package dustin.examples;
import static java.lang.System.out;
/**
* Simple example class that demonstrates functionality on Java arrays.
*/
public class JavaArrays
{
public static void main(final String[] arguments)
{
final Person[] objectArray =
{ new Person("Flintstone", "Fred"), new Person("Rubble", "Barney") };
out.println("Length of array is " + objectArray.length);
out.println("Array toString is " + objectArray.toString());
}
}
When the above code is executed, the output looks like that shown in the next screen snapshot:

The output of a
toString call on an array is not very helpful. As I discussed in the blog post Java Arrays: Copying, String Representation, and Collections, the java.util.Arrays class provides some useful methods for dealing with arrays. In Groovy, many of these same convenient methods are available directly on the arrays themselves thanks to Object[] and T[]. In the remainder of this blog post, I will look at some of these direct Groovy array method support in detail.In this first snippet from my Groovy script
groovyObjectArray.groovy, the Object[].asType(Class) method is demonstrated. This method allows an array of Objects to be treated as a Set of Objects or a List of Objects. The version that provides a SortedSet is commented out because the objects in the collection need to be Comparable for a
SortedSet and our custom Person class is not Comparable.groovyObjectArray.groovy (part 1)
import dustin.examples.Person
Object[] objectArray = [new Person("Flintstone", "Fred"), new Person("Rubble", "Barney")]
println "objectArray's class type: ${objectArray.getClass().name}"
objectSet = objectArray.asType(java.util.Set)
println "objectSet's class type: ${objectSet.getClass().name}"
objectList = objectArray.asType(java.util.List)
println "objectList's class type: ${objectList.getClass().name}"
// Running Object[].asType(java.util.SortedSet) requires elements in array of
// objects to implement the Comparable interface because that is a requirement
// of java.util.SortedSet. A ClassCastException is encountered if the objects
// do not implement Comparable: "cannot be cast to java.util.Comparable"
//objectSortedSet = objectArray.asType(java.lang.SortedSet)
//println "objectSortedSet's class type: ${objectSortedSet.getClass().name}"
The output for these first few lines of Groovy code is shown next.

Object[] provides several more useful and convenient methods for accessing array elements. Some of these (Object[].size(), Object[].toArrayString(), Object[].toString(), Object[].join(), and Object[].count()) are shown in the next code listing, the second part of the script groovyObjectArray.groovy.groovyObjectArray.groovy (part 2)
println "objectArray #items (.length property): ${objectArray.length}"
println "objectArray #items (size() method): ${objectArray.size()}"
println "objectArray toArrayString: ${objectArray.toArrayString()}"
println "objectArray toString: ${objectArray.toString()}"
println "objectArray join with <--->: ${objectArray.join('<--->')}"
// The Object[].count method requires Groovy 1.6.4.
personToMatch = new Person("Flintstone", "Fred")
println "objectArray #contained items: ${objectArray.count(personToMatch)}"
The output from the above snippet of the script is shown next.

As the above code listing and its corresponding output indicate, the Object[].toString() and Object[].toArrayString() methods provide nice String representations of the array contents. The Object[].size() method is a method-based approach to get the size or length of the array. The Object[].join(String) method joins the String representations of the elements of the array to each other with the provided String-based separator joining them. The Object[].count(Object) method has only been available since Groovy 1.6.4 and provides the number of instances of the provided Object within that array.
The third and final part of the
groovyObjectArray.groovy script demonstrates the useful methods on T[] that provide minimum and maximum values of the elements of the array. The elements need to be comparable for these to work and I use Strings, integers, and doubles respectively.groovyObjectArray.groovy (part 3)
// Use methods on T[]
Object[] stringArray = ["One", "Two", "Three", "Four", "Five"]
Object[] integerArray = [1, 2, 3, 4 ,5]
Object[] doubleArray = [1.0, 2.5, 5.0, 7.5, 10.0]
println "stringArray.max(): ${stringArray.max()}"
println "stringArray.min(): ${stringArray.min()}"
println "integerArray.max(): ${integerArray.max()}"
println "integerArray.mix(): ${integerArray.min()}"
println "doubleArray.max(): ${doubleArray.max()}"
println "doubleArray.min(): ${doubleArray.min()}"
The output from the above is shown in the next screen snapshot.

This posting has demonstrated the useful convenience methods provided for array access and manipulation in Groovy GDK with Object[] and T[].
Thứ Sáu, 2 tháng 10, 2009
Groovy JDK (GDK): List Enhancements
In prior blog posts, I have discussed several highly useful classes and methods provided as part of the Groovy JDK (GDK). These posts have covered GDK-extended classes such as File, String, and Number. In this post, I cover GDK's extension of one of the most popular interfaces in the Java Collections Framework: the List.
The GDK List extension provides numerous convenient methods and includes methods that provide mathematical operator support for
In my first code listing, I set up two
I included a println statement after each variable declaration that prints out the type of concrete class actually being used. As the output in the next screen snapshot indicates, an ArrayList is implicitly applied in both cases.

With two lists prepared, we can start using GDK's extended List functions to operate on these lists. I have blogged previously about using the Java Collections class to make provide a Collection that is immutable or a to provide a Collection that is synchronized. The GDK
The output from the above code is shown in the next screen output. We see that the same type of objects returned from the respective Collections methods are returned here.

The GDK List class adds methods for accessing the first element, the last element, the head (first element), or the tail elements (all elements except the head element). These four methods are demonstrated in the next (third) code listing.
The output corresponding to the code listing directly above is shown next.

Groovy makes it really easy to generate a
The output from running the above Groovy code is shown next.

During my transition from being primarily a C++ developer to being primarily a Java developer, I often found myself missing operator overloading. Groovy brings it back in the Java world. One example of this is the support for the
The GDK
The following output demonstrates that these

The Groovy GDK
This code's output is shown next with Massachusetts and Boston missing from their respective

As a potential preview of what is to come with Java SE 7, Groovy supports subscript notation for Lists. What this means is that individual elements of a GDK List can be accessed in an array-like fashion.
The above Groovy code places "Idaho" and "Boise" back in the original

The GDK List.reverseEach(Closure) method allows one to iterate in reverse order over the target List and invoke the provided closure on each item iterated over. The following code demonstrates this with a very simplistic closure that simply prints the currently iterated element's String contents.
The output for the above code is shown next.

I previously blogged about the GDK String.execute() method that allows the String upon which that call is invoked to be executed against the underlying operating system. The GDK
An example of this is shown in the next code listing (Windows-specific example):
The output from the above is actually simply the entire Groovy script containing the code examples in this post. For brevity, I only show the bottom of that output here.

The GDK List adds several convenience methods and operator support to the standard JDK List. This makes
The GDK List extension provides numerous convenient methods and includes methods that provide mathematical operator support for
Lists. In this blog post, I look at several of these methods and operators provided by the Groovy extended List.In my first code listing, I set up two
Lists. The first is set up without any explicit specification of interface or implementation. The second is set up with explicit interface declared, but no specific implementation of that interface is specified.
println "====== SET UP TWO LISTS ====="
// Obtain a List implicitly (dynamic typing)
implicitList = ["Arizona", "New Mexico", "Colorado", "Massachusetts", "Utah", "Wyoming"]
println "Implicit: ${implicitList.getClass().name}"
// Explicitly specify List interface, but rely on implementation implicitly
List explicitList = ["Phoenix", "Santa Fe", "Denver", "Boston", "Salt Lake City", "Cheyenne"]
println "Explicit: ${explicitList.getClass().name}\n"
I included a println statement after each variable declaration that prints out the type of concrete class actually being used. As the output in the next screen snapshot indicates, an ArrayList is implicitly applied in both cases.

With two lists prepared, we can start using GDK's extended List functions to operate on these lists. I have blogged previously about using the Java Collections class to make provide a Collection that is immutable or a to provide a Collection that is synchronized. The GDK
List class makes these Collections.unmodifiableList(List) and Collections.synchronizedList(List) methods even easier to use directly on the List with its List.asImmutable() and List.asSynchronized() methods. These are demonstrated in the next (second) code listing.
// Demonstrate easy access to immutable version of List
List immutableList = implicitList.asImmutable()
println "List.asImmutable: ${immutableList.getClass().name}"
println "Collections.unmodifiableList: ${Collections.unmodifiableList(implicitList).getClass().name}\n"
// Demonstrate easy access to synchronized version of List.
List synchronizedList = implicitList.asSynchronized();
println "List.asSynchronized: ${synchronizedList.getClass().name}"
println "Collections.synchronizedList: ${Collections.synchronizedList(implicitList).getClass().name}\n"
The output from the above code is shown in the next screen output. We see that the same type of objects returned from the respective Collections methods are returned here.

The GDK List class adds methods for accessing the first element, the last element, the head (first element), or the tail elements (all elements except the head element). These four methods are demonstrated in the next (third) code listing.
// Demonstrate List.first()/List.head() and List.last()/List.tail()
println "First state is ${implicitList.first()} and last state is ${implicitList.last()}"
println "Head state is ${implicitList.head()} and tail states are ${implicitList.tail()}\n"
The output corresponding to the code listing directly above is shown next.

Groovy makes it really easy to generate a
List with entries in the reverse order of the original List via its GDK List.reverse() method. This is demonstrated in the next (fourth) code listing.
// Demonstrate List.reverse()
reverseList = implicitList.reverse();
println "Content of reverseList: $reverseList\n"
The output from running the above Groovy code is shown next.

During my transition from being primarily a C++ developer to being primarily a Java developer, I often found myself missing operator overloading. Groovy brings it back in the Java world. One example of this is the support for the
+ operator supported by Groovy's GDK List. The next example demonstrates adding an element to a List using the + operator and adding another List (in this case a single-element List) to the original List using the + operator.
// Demonstrate plus (+) operator
implicitList += "Montana"
println "Montana added with +: $implicitList"
explicitList += ["Helena"]
println "Helena added with +: $explicitList\n"
The GDK
List supports LIFO stack semantics with its List.push(T) and List.pop() methods, demonstrated in the next code example.
// Demonstrate List.push()
implicitList.push "Idaho"
println "Implicit with push-ed Idaho: $implicitList"
explicitList.push "Boise"
println "Explicit with pushed-ed Boise: $explicitList\n"
// Demonstrate List.pop()
implicitList.pop()
println "Implicit after pop-ed: $implicitList"
explicitList.pop()
println "Explicit after pop-ed: $explicitList\n"
The following output demonstrates that these
List.push(T) and List.pop() methods work as we would expect.
The Groovy GDK
List class supports the - operator similarly to how it supports the + operator. The following code snippet demonstrates removing one List from another using List.minus(Collection) method (there is also an overloaded version for removing an individually provided object) and using the - operator.
// Demonstrate minus and "-"
rockyMountainStates = implicitList.minus("Massachusetts")
println "Rocky Mountain States (after 'minus'): $rockyMountainStates"
capitalsToRemove = ["Boston"]
rockyMountainCapitals = explicitList - capitalsToRemove
println "Rocky Mountain Capitals (after '-'): $rockyMountainCapitals\n";
This code's output is shown next with Massachusetts and Boston missing from their respective
Lists.
As a potential preview of what is to come with Java SE 7, Groovy supports subscript notation for Lists. What this means is that individual elements of a GDK List can be accessed in an array-like fashion.
// Use subscript operator to replace Massachusets/Boston with Idaho/Boise
implicitList[3] = "Idaho"
println "Put implicitList[3]: $implicitList"
explicitList[3] = "Boise"
println "Put explicitList[3]: $explicitList\n"
// Demonstrate retrieving by subscript operator
println "Get implicitList[2]: ${implicitList[2]}"
println "Get explicitList[2]: ${explicitList[2]}\n"
The above Groovy code places "Idaho" and "Boise" back in the original
Lists in place of "Massachusetts" and "Boston" respectively. Then, the elements for "Colorado" and "Denver" are extracted from the Lists. Both the setting and the getting of elements of the underlying List were accomplished using [index] syntax where index is a 0-based index value. The output is shown next.
The GDK List.reverseEach(Closure) method allows one to iterate in reverse order over the target List and invoke the provided closure on each item iterated over. The following code demonstrates this with a very simplistic closure that simply prints the currently iterated element's String contents.
// Demonstrate reverse iteration with simple closure
implicitList.reverseEach() {println it}
The output for the above code is shown next.

I previously blogged about the GDK String.execute() method that allows the String upon which that call is invoked to be executed against the underlying operating system. The GDK
List class provides a similar List.execute() method that expects the first list item to be the actual command to be executed and the remaining list elements to be the parameters to that command. In other words, List.head() should provide the command in a List built to be used with execute() and List.tail() should provide the parameters to that command.An example of this is shown in the next code listing (Windows-specific example):
// Demonstate List.process
commandList = ["cmd", "/C", "type", "groovyList.groovy"]
println "${commandList.execute().text}"
The output from the above is actually simply the entire Groovy script containing the code examples in this post. For brevity, I only show the bottom of that output here.

The GDK List adds several convenience methods and operator support to the standard JDK List. This makes
List data structures easier than ever to use and gives us a taste of what may come in future versions of Java.
Đăng ký:
Bài đăng (Atom)